Enable Automatic backups after switchover using OCI Functions

There is an unpleasant thing you may know with regards to Data Guard with DBCS in OCI. If you are running a database in OCI then it is highly probable that it is DBCS. DBCS comes with very useful feature called Automatic backups. Until this point all is absolutely perfect.
The problem is when you are using DBCS with Data Guard and you perform a switchover from Primary to Standby and then back. Expected behavior would be that Automatic backups keep running once you are back to Primary. Unfortunately it is not true.

When I asked Oracle support about this problem they wrote me it is expected behavior.

Well I don’t like it. So I have made so called Event driven Function in OCI to ensure that Automatic backups will be enabled once switchover is over and original Primary become the Primary again.
Prerequisites
- You have working environment in OCI with two DBCS instances in Data Guard setup.
- Your OCI user has enough privileges to manage Functions, Rules and DBCS.
- You don’t need any 3rd party tool. All we will do in OCI Console.
Initial configuration
1. To allow a Function to manipulate with DBCS you have to create a dynamic group allowing interacting with resources in the compartment where your DBCS resides.
ALL{resource.type = ‘fnfunc’, resource.compartment.id = ‘ocid1.compartment.oc1..aaaaa...’}

2. When you have the dynamic group you have to add a policy to it. The policy allows the Function to manipulate with entire Database family. It is recommended to narrow down the privileges to the least needed but for the sake of simplicity I will stick to managing entire Database family.
Allow dynamic-group FuncionsDG to manage database-family in compartment YourCompartment

3. When the dynamic group and policy is in place you need to generate Auth Token for accessing Container Registry. This you can do on your user who will be creating the Function. In Resources click on Auth Token and Generate Token. Once the Token is generated save it somewhere aside as it will not show again when you close the message. The Token will be needed in 6th step of Getting started section below.


Function creation
1. Now we can move on to the creation of the Function. Functions are located under Developer Services in OCI Console. But as the first step you have to create an Application as functions belongs to an application. Let’s give it a name “db_app”. I recommend you to use only lowercase as it will make your life easier because some of the resources like repository or function name requires to use only lowercase.

2. Let’s create the Function now. OCI offers very easy and straight forward steps in Getting started section of every application. You can follow steps 1–7 as these steps are already prefilled by information from your OCI Compartment and Tenancy.


3. Continue in Cloud Shell with initializing of the Function.
peter_pros@cloudshell:~ (eu-frankfurt-1)$ fn init --runtime python auto_backups
Creating function at: ./auto_backups
Function boilerplate generated.
func.yaml created.
peter_pros@cloudshell:~ (eu-frankfurt-1)$ cd auto_backups/
peter_pros@cloudshell:auto_backups (eu-frankfurt-1)$ ll
total 12
-rw-r--r--. 1 peter_pros oci 576 Jun 19 19:51 func.py
-rw-r--r--. 1 peter_pros oci 211 Jun 19 19:51 func.yaml
-rw-r--r--. 1 peter_pros oci 11 Jun 19 19:51 requirements.txt
peter_pros@cloudshell:auto_backups (eu-frankfurt-1)$
4. Open func.py with Vim (or Code Editor) then remove exiting code and put inside following code. Then Save.
import oci
import io
import json
from os import getenv
from fdk import response
def handler(ctx, data: io.BytesIO=None):
signer = oci.auth.signers.get_resource_principals_signer()
resp = update_aut_backup_dbcs(signer)
return response.Response(
ctx,
response_data=resp,
headers={"Content-Type": "application/json"}
)
def update_aut_backup_dbcs(signer):
database_client = oci.database.DatabaseClient(config={}, signer=signer)
dbid = getenv('dbid')
auto_backup = getenv('auto_backup')
retention = getenv('retention')
inc_backup_window = getenv('inc_backup_window')
full_backup_window = getenv('full_backup_window')
full_backup_day = getenv('full_backup_day')
update_database_response = database_client.update_database(
database_id=dbid,
update_database_details=oci.database.models.UpdateDatabaseDetails(
db_backup_config=oci.database.models.DbBackupConfig(
auto_backup_enabled=eval(auto_backup),
recovery_window_in_days=int(retention),
auto_backup_window=inc_backup_window,
auto_full_backup_window=full_backup_window,
auto_full_backup_day=full_backup_day,
backup_destination_details=[
oci.database.models.BackupDestinationDetails(
type="OBJECT_STORE")])))
return update_database_response.data
5. Open func.yaml then remove exiting code and put inside following code. Then Save.
schema_version: 20180708
name: auto_backups
version: 0.0.1
runtime: python
build_image: fnproject/python:3.9-dev
run_image: fnproject/python:3.9
entrypoint: /python/bin/fdk /function/func.py handler
memory: 256
6. Open requirements.txt then remove exiting code and put inside following code. Then Save.
fdk>=0.1.57
oci>=2.46.0
7. At this point the Function is almost ready. Now you must deploy the Application in Cloud Shell which will create a Docker container in your registry.
$ fn -v deploy --app db_app
At the end of the process you should see Successful message.
Updating function auto_backups using image fra.ocir.io/...
Successfully created function: auto_backups with fra.ocir.io/...
8. Add configuration to the Function. In OCI Console in Applications where you have opened your “db_app” application click Functions located in Resources. Then click on the function name.

In the Function click on Configuration and fill the key value pairs with your desired values. The values you should take from your existing Automatic backup configuration. Backup windows are marked as SLOTs in API calls. The SLOTs works following SLOT_ONE = 12:00AM — 2:00AM, SLOT_TWO = 2:00AM — 4:00AM, and so on… Checkbox “Take the first backup immediately” is not working over API at the time of writing this article.
full_backup_window: SLOT_TWO
full_backup_day: SUNDAY
retention: 15
auto_backup: True
inc_backup_window: SLOT_ONE
dbid: ocid1.database.oc1.eu-frankfurt-1.ant...

9. (Optional) If you want you can test it now from Cloud Shell by invoking the function. If you closed Cloud Shell then before you run the Function you must enter the directory of the function “cd auto_backups”.
$ fn invoke db_app auto_backups
If all works properly you should get JSON output of the DB details and Automatic backups on the DB should be updated according to your parameters.
10. If something goes wrong then you usually get the 502 error. For troubleshooting enable Logging on the application (Logs under Resources).
Event creation
1. Navigate to Rules in OCI Console. Rules are located Observability & Management -> Events Service in OCI Console.
2. Let’s create a Rule that will enable Automatic backups once switchover is finished. Just keep in mind that we want to enable backup on original Primary so after second switchover (from original Standby back to original Primary). Hence we will need details from original Standby database. What you need to set is Service Name = Database and Event Type = Data Guard Association — Switchover End. Then you must specify Attribute which is DatabaseId = database OCID of original Standby. Then tell to the Rule what action should be taken. In this case it is clear as it suppose to trigger a “auto_backups” function from “db_app” application that we just created.

Testing switchover
Now you are ready to test the switchover. You will switch from Primary to Standby and when completed then you will switch back. Automatic backups will enable once the switch back is completed.