Version 1.0.4 of the oggrestapi Python client is on PyPI. The previous release post, GoldenGate REST API Python client now on pip, explains how to install and use the package. To upgrade, run pip install --upgrade oggrestapi, or replace the oggrestapi.py script with the latest version if you use the script directly. The full list of changes is in the changelog of the repository. Some changes break existing scripts, so the last section lists them. The examples below are recorded sessions of version 1.0.4 against a 23.26.4.0.0 deployment, where client is an OGGRestAPI object.

What is new

Update, recreate or verify an existing resource

Until now, if_exists accepted 'fail' (the default) and 'skip'. It now accepts three more values: 'update', 'recreate' and 'verify'. Each one acts only when the create returns a 409, meaning that the resource already exists. The accepted values are listed in the IF_EXISTS_VALUES class attribute, and an unknown value, such as 'Skip', raises a ValueError instead of behaving like 'fail'.

The first one is 'verify'. It reads the resource and raises a RuntimeError that names each field that differs from the request. Secrets such as password and fields such as status are not compared. In the session below, the extract is created, then verified against the same request, then verified again after a table is added to the parameters.

>>> config = [
...     'EXTRACT EXTREL',
...     'USERIDALIAS oggadmin_pdb1 DOMAIN OracleGoldenGate',
...     'EXTTRAIL rl',
...     'TABLE OGGADMIN.SMK264;',
... ]

>>> client.create_extract(
...     'EXTREL',
...     begin='now',
...     config=config,
...     source='tranlogs',
...     credentials={'alias': 'oggadmin_pdb1', 'domain': 'OracleGoldenGate'},
...     targets=[{'name': 'rl'}],
...     status='stopped',
... )['messages'][0]['title']
'Integrated Extract added.'

>>> client.create_extract(
...     'EXTREL',
...     begin='now',
...     config=config,
...     source='tranlogs',
...     credentials={'alias': 'oggadmin_pdb1', 'domain': 'OracleGoldenGate'},
...     targets=[{'name': 'rl'}],
...     status='stopped',
...     if_exists='verify',
... )['status']
'verified'

>>> config.append('TABLE OGGADMIN.SMK265;')

>>> client.create_extract(
...     'EXTREL',
...     begin='now',
...     config=config,
...     source='tranlogs',
...     credentials={'alias': 'oggadmin_pdb1', 'domain': 'OracleGoldenGate'},
...     targets=[{'name': 'rl'}],
...     status='stopped',
...     if_exists='verify',
... )
RuntimeError: The extract with name 'EXTREL' already exists. Existing resource differs from the request: config: missing ['TABLE OGGADMIN.SMK265;']

With 'update', the client sends the full body for endpoints that use PUT, and returns updated. For endpoints that use PATCH, it reads the resource first and sends only the fields that changed. It returns unchanged without sending any request when nothing differs. The profile example further down shows 'update' on a PUT endpoint. The 'skip' value leaves the resource as it is and returns skipped.

>>> client.create_extract(
...     'EXTREL',
...     config=config,
...     if_exists='skip',
... )['status']
'skipped'

With 'recreate', the client deletes the resource and creates it again. For an extract, the trail files are purged between the two, because delete_extract leaves them on disk, and the client waits recreate_wait_seconds (20 seconds by default) before the create.

>>> client.create_extract(
...     'EXTREL',
...     begin='now',
...     config=config,
...     source='tranlogs',
...     credentials={'alias': 'oggadmin_pdb1', 'domain': 'OracleGoldenGate'},
...     targets=[{'name': 'rl'}],
...     status='stopped',
...     if_exists='recreate',
... )['status']
'recreated'

>>> client.get_extract('EXTREL')['config'][-2:]
['TABLE OGGADMIN.SMK264;', 'TABLE OGGADMIN.SMK265;']

Lag getters

get_extract_lag, get_replicat_lag and get_distribution_path_lag return the lag in seconds. By default, the value is lag plus sinceLagReported, because the reported lag stops changing once a process stops updating it. With include_since_reported=False, the methods return the raw lag. They return None when no lag is reported.

In the session below, the extract is started and abends a few seconds later. The raw lag is 0, and the default value is 10, the time since the last report. After the abend, the default value is still 10.

>>> client.start_extract('EXTREL')['messages'][-1]['title']
'Extract group EXTREL started.'

>>> time.sleep(10)

>>> client.get_extract_lag('EXTREL')
10

>>> client.get_extract_lag('EXTREL', include_since_reported=False)
0

>>> client.get_extract('EXTREL')['status']
'abended'

>>> client.get_extract_lag('EXTREL')
10

Trail purge

purge_trail purges trail files through execute_command, on 19c, 23ai and 26ai. Files are purged from the oldest sequence forward, and keep_files, keep_hours and keep_days limit what is removed. With use_checkpoints=True (the default), the purge stops before the files still read by a replicat or a distribution path. It aborts if a process that uses the trail has no valid CSN (OGG-30661) or if its extract is not running (OGG-30827). With use_checkpoints=False, it also deletes the file that a running extract is writing. The extract above is not running, so the purge with checkpoints is refused. Without checkpoints, it runs, but the trail rl has no file yet.

>>> client.purge_trail('rl')['messages'][0]['title']
"Trail purge for trail 'rl' was aborted because the producer process has status 'stopped'."

>>> client.purge_trail('rl', use_checkpoints=False)['messages'][0]['title']
'No files found for specified trails.'

Managed process profiles

create_managed_process_profile creates a profile from named settings instead of a raw data dictionary, and delete_managed_process_profile deletes it. Like ADD PROFILE in the adminclient, the create method writes both the ogg:managedProcessSettings value and its ogg:configDataDescription entry. It accepts if_exists like the other create methods, so a profile can be verified or updated the same way.

>>> client.create_managed_process_profile(
...     'RelProf',
...     auto_restart=True,
...     restart_delay=15,
...     restart_retries=4,
... )['messages']
[]

>>> client.create_managed_process_profile(
...     'RelProf',
...     auto_restart=True,
...     restart_delay=30,
...     restart_retries=4,
...     if_exists='verify',
... )
RuntimeError: The value with name 'ogg:managedProcessSettings:RelProf' already exists. Existing resource differs from the request: autoRestart.delay: requested 30, existing 15

>>> client.create_managed_process_profile(
...     'RelProf',
...     auto_restart=True,
...     restart_delay=30,
...     restart_retries=4,
...     if_exists='update',
... )['status']
'updated'

>>> client.get_config_value(type='ogg:managedProcessSettings', value='ogg:managedProcessSettings:RelProf')['autoRestart']
{'enabled': True, 'onSuccess': False, 'delay': 30, 'retries': 4, 'window': 60, 'disableOnFailure': True}

>>> client.delete_managed_process_profile('RelProf')['messages']
[]

With GoldenGate 23.26.4.0.0, the new managed_path_settings argument of create_distribution_path, update_distribution_path, create_receiver_path and update_receiver_path assigns such a profile to a path. The server refuses it together with explicit auto-restart options (OGG-30812). The post about the distribution path profile tests it in detail.

Changes that can break a script

  • AI service methods are renamed. The Service Manager methods drop installation_, so create_installation_ai_service_provider becomes create_ai_service_provider. The read-only methods of the Administration Server become list_deployment_ai_service_models and get_deployment_ai_service_model. The old names are removed, with no aliases.
  • Every error response raises a RuntimeError. An error whose body has an empty messages list, as the AI service endpoints return, used to raise requests.HTTPError.
  • if_exists is stricter. It raises a ValueError for an unknown value and for a value that the endpoint cannot handle, such as 'update' on create_config_type. create_master_key_version, add_cluster_member and create_configuration_service_backend no longer take if_exists, and 'recreate' is refused on create_deployment and create_cluster, because deleting either removes everything it contains.

One bug is fixed: _extract_main no longer fails with a TypeError on an empty response body, for instance after an AI service DELETE.