Skip to content

Commit 9bfdb84

Browse files
Releasing version 2.129.2
Releasing version 2.129.2
2 parents 3b41b29 + fa238d1 commit 9bfdb84

File tree

16 files changed

+2008
-17
lines changed

16 files changed

+2008
-17
lines changed

CHANGELOG.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ Change Log
33
All notable changes to this project will be documented in this file.
44

55
The format is based on `Keep a Changelog <http://keepachangelog.com/>`_.
6+
====================
7+
2.129.2 - 2024-07-09
8+
====================
9+
10+
Added
11+
-----
12+
* Support for cost management of shared resources in the Usage service
13+
* Support for creating new databases with oracle key vault on Exadata Cloud at Customer in the Database service
14+
* Support for confirming key store details on Exadata Cloud at Customer in the Database service
15+
616
====================
717
2.129.1 - 2024-07-02
818
====================
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import os
2+
import oci
3+
import sys
4+
import time
5+
from oci.object_storage import UploadManager
6+
from oci.object_storage.transfer.constants import MEBIBYTE
7+
from oci.object_storage.transfer.internal.download.DownloadConfiguration import DownloadConfiguration
8+
from oci.object_storage.transfer.internal.download.DownloadManager import DownloadManager
9+
from oci.object_storage.transfer.internal.download.DownloadThread import DownloadState
10+
from oci.retry.retry import NoneRetryStrategy, BACKOFF_FULL_JITTER_VALUE
11+
from oci.exceptions import ResumableDownloadException, DownloadTerminated
12+
13+
14+
def upload_progress_callback(bytes_uploaded):
15+
print(f"{bytes_uploaded} additional bytes uploaded")
16+
17+
18+
def on_press(key, download_manager):
19+
try:
20+
if key.char == 'p':
21+
if download_manager.state == 0:
22+
print("Download Paused!\n")
23+
download_manager.state = 1
24+
return
25+
26+
if download_manager.state == 1:
27+
print("Download Resumed!\n")
28+
download_manager.state = 0
29+
return
30+
31+
if key.char == 'q':
32+
print("Terminating Download!\n")
33+
download_manager.state = -1
34+
return
35+
36+
except AttributeError:
37+
pass
38+
39+
40+
def print_progress_bar(downloaded_bytes, total_bytes, bar_length=60):
41+
if (total_bytes == 0):
42+
print(f"Starting Download\n[{'#' * 0 + '-' * (bar_length - 0)}] {0 * 100:.2f}%")
43+
else:
44+
progress = downloaded_bytes / total_bytes
45+
block = int(round(bar_length * progress))
46+
progress_bar = f"[{'#' * block + '-' * (bar_length - block)}] {progress * 100:.2f}%"
47+
48+
CURSOR_UP_ONE = '\x1b[1A'
49+
ERASE_LINE = '\x1b[2K'
50+
sys.stdout.write(CURSOR_UP_ONE)
51+
sys.stdout.write(ERASE_LINE)
52+
sys.stdout.write(CURSOR_UP_ONE)
53+
sys.stdout.write(ERASE_LINE)
54+
print(f"Downloading: {downloaded_bytes}/{total_bytes} bytes\n{progress_bar}")
55+
sys.stdout.flush()
56+
57+
58+
if __name__ == '__main__':
59+
"""
60+
This example program works as follows.
61+
1) First we upload an object to an existing bucket.
62+
2) Then we download it.
63+
3) While the download is in progress, press p on the keyboard to pause the download and p again to resume, q to
64+
cancel the download.
65+
# Please note that while the download is in progress don't type else where as the key presses will be registered as
66+
pause or terminate signals.
67+
68+
Below are the parameters that are to be filled. Running this program in the terminal is good option as the download
69+
progress is seen better that way.
70+
71+
PLEASE NOTE THAT THIS EXAMPLE USES pynput (pip install pynput) so it is advisable to re install all packages in the
72+
requirements.txt.
73+
74+
Use `diff uploaded_file_name downloaded_file_name` in the terminal to check if the uploaded and downloaded files are
75+
the same.
76+
77+
The Progress call back can add significant delays to the overall download speed.
78+
79+
Fill the following parameters:
80+
"""
81+
namespace = "bm2ywytyr7us" # Put your namespace
82+
bucket_name = "bucket-20240527-1635" # Put your bucket name
83+
object_name = "11MB_dummy.txt" # Put your object name or leave it as it is.
84+
upload_filename = r'11MB_dummy.txt'
85+
download2path = r'down_11MB_dummy.txt'
86+
file_size_in_mebibytes = 11
87+
part_size = int(1 * MEBIBYTE)
88+
num_connections = 4
89+
90+
print(f"Part size is {part_size} MB")
91+
print(f"Number of connections is {num_connections}")
92+
93+
object_storage_client_config = oci.config.from_file()
94+
95+
compartment_id = object_storage_client_config["tenancy"]
96+
object_storage = oci.object_storage.ObjectStorageClient(object_storage_client_config)
97+
98+
# create example file to upload
99+
sample_content = b'a'
100+
with open(upload_filename, 'wb') as f:
101+
while f.tell() < MEBIBYTE * file_size_in_mebibytes:
102+
f.write(sample_content * MEBIBYTE)
103+
104+
print(f"Uploading new object {object_name!r}")
105+
106+
start_time = time.time()
107+
upload_manager = UploadManager(object_storage, allow_parallel_uploads=True, parallel_process_count=num_connections)
108+
response = upload_manager.upload_file(
109+
namespace, bucket_name, object_name, upload_filename, part_size=part_size)
110+
111+
end_time = time.time()
112+
print("Time taken to upload file: ", end_time - start_time)
113+
114+
download_configuration = DownloadConfiguration(allow_multipart=True, num_download_threads=num_connections,
115+
part_size_in_bytes=part_size, max_retries=1,
116+
backoff_type=BACKOFF_FULL_JITTER_VALUE)
117+
118+
download_manager = DownloadManager(download_configuration, object_storage, DownloadState.DOWNLOADING)
119+
120+
print_progress_bar(0, 0)
121+
122+
start = time.time()
123+
retry_strategy = NoneRetryStrategy()
124+
try:
125+
bytes_written, down_response = download_manager.get_object_to_path(namespace, bucket_name, object_name,
126+
download2path,
127+
progress_callback=print_progress_bar)
128+
end = time.time()
129+
print("--------------------------------------------------------")
130+
print("Download Headers:\n", down_response.headers)
131+
print("Download took {} seconds".format(end - start))
132+
os.remove(upload_filename)
133+
os.remove(download2path)
134+
135+
except Exception as e:
136+
exception = e
137+
while True:
138+
if isinstance(exception, ResumableDownloadException):
139+
print("Failed parts: ", exception.failed_parts)
140+
ans = (input(
141+
"Retry the failed parts parallely using resume_parts_to_path_multithread() method? [y/n] ").strip().lower())
142+
143+
if ans == "y":
144+
try:
145+
_ = download_manager.resume_parts_to_path_multithread(namespace, bucket_name, object_name,
146+
list(exception.failed_parts.keys()),
147+
download2path)
148+
os.remove(upload_filename)
149+
os.remove(download2path)
150+
break # Exit the loop after retrying
151+
except ResumableDownloadException as e:
152+
print("ResumableDownloadException occurred again.")
153+
exception = e
154+
continue
155+
except Exception as retry_exception:
156+
raise retry_exception
157+
# Exit the loop if an unexpected exception occurs during retry
158+
else:
159+
break # Exit the loop if the user chooses not to retry
160+
elif isinstance(exception, DownloadTerminated):
161+
print("Download was terminated")
162+
break
163+
else:
164+
raise exception

src/oci/database/database_client.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4168,6 +4168,120 @@ def configure_saas_admin_user(self, autonomous_database_id, configure_saas_admin
41684168
api_reference_link=api_reference_link,
41694169
required_arguments=required_arguments)
41704170

4171+
def confirm_key_store_details_are_correct(self, key_store_id, **kwargs):
4172+
"""
4173+
This is for user to confirm to DBaaS that the Oracle Key Valut (OKV) connection IPs, username and password are all correct. This operation will put
4174+
the Key Store back into Active state. If details are incorrect, your OKV account may get locked after some unsuccessful attempts to connect.
4175+
4176+
4177+
:param str key_store_id: (required)
4178+
The `OCID`__ of the key store.
4179+
4180+
__ https://docs.cloud.oracle.com/Content/General/Concepts/identifiers.htm
4181+
4182+
:param str opc_retry_token: (optional)
4183+
A token that uniquely identifies a request so it can be retried in case of a timeout or
4184+
server error without risk of executing that same action again. Retry tokens expire after 24
4185+
hours, but can be invalidated before then due to conflicting operations (for example, if a resource
4186+
has been deleted and purged from the system, then a retry of the original creation request
4187+
may be rejected).
4188+
4189+
:param str opc_request_id: (optional)
4190+
Unique identifier for the request.
4191+
4192+
:param str if_match: (optional)
4193+
For optimistic concurrency control. In the PUT or DELETE call for a resource, set the `if-match`
4194+
parameter to the value of the etag from a previous GET or POST response for that resource. The resource
4195+
will be updated or deleted only if the etag you provide matches the resource's current etag value.
4196+
4197+
:param obj retry_strategy: (optional)
4198+
A retry strategy to apply to this specific operation/call. This will override any retry strategy set at the client-level.
4199+
4200+
This should be one of the strategies available in the :py:mod:`~oci.retry` module. This operation will not retry by default, users can also use the convenient :py:data:`~oci.retry.DEFAULT_RETRY_STRATEGY` provided by the SDK to enable retries for it.
4201+
The specifics of the default retry strategy are described `here <https://docs.oracle.com/en-us/iaas/tools/python/latest/sdk_behaviors/retries.html>`__.
4202+
4203+
To have this operation explicitly not perform any retries, pass an instance of :py:class:`~oci.retry.NoneRetryStrategy`.
4204+
4205+
:param bool allow_control_chars: (optional)
4206+
allow_control_chars is a boolean to indicate whether or not this request should allow control characters in the response object.
4207+
By default, the response will not allow control characters in strings
4208+
4209+
:return: A :class:`~oci.response.Response` object with data of type None
4210+
:rtype: :class:`~oci.response.Response`
4211+
4212+
:example:
4213+
Click `here <https://docs.cloud.oracle.com/en-us/iaas/tools/python-sdk-examples/latest/database/confirm_key_store_details_are_correct.py.html>`__ to see an example of how to use confirm_key_store_details_are_correct API.
4214+
"""
4215+
# Required path and query arguments. These are in camelCase to replace values in service endpoints.
4216+
required_arguments = ['keyStoreId']
4217+
resource_path = "/keyStores/{keyStoreId}/actions/confirmDetailsAreCorrect"
4218+
method = "POST"
4219+
operation_name = "confirm_key_store_details_are_correct"
4220+
api_reference_link = "https://docs.oracle.com/iaas/api/#/en/database/20160918/KeyStore/ConfirmKeyStoreDetailsAreCorrect"
4221+
4222+
# Don't accept unknown kwargs
4223+
expected_kwargs = [
4224+
"allow_control_chars",
4225+
"retry_strategy",
4226+
"opc_retry_token",
4227+
"opc_request_id",
4228+
"if_match"
4229+
]
4230+
extra_kwargs = [_key for _key in six.iterkeys(kwargs) if _key not in expected_kwargs]
4231+
if extra_kwargs:
4232+
raise ValueError(
4233+
f"confirm_key_store_details_are_correct got unknown kwargs: {extra_kwargs!r}")
4234+
4235+
path_params = {
4236+
"keyStoreId": key_store_id
4237+
}
4238+
4239+
path_params = {k: v for (k, v) in six.iteritems(path_params) if v is not missing}
4240+
4241+
for (k, v) in six.iteritems(path_params):
4242+
if v is None or (isinstance(v, six.string_types) and len(v.strip()) == 0):
4243+
raise ValueError(f'Parameter {k} cannot be None, whitespace or empty string')
4244+
4245+
header_params = {
4246+
"accept": "application/json",
4247+
"content-type": "application/json",
4248+
"opc-retry-token": kwargs.get("opc_retry_token", missing),
4249+
"opc-request-id": kwargs.get("opc_request_id", missing),
4250+
"if-match": kwargs.get("if_match", missing)
4251+
}
4252+
header_params = {k: v for (k, v) in six.iteritems(header_params) if v is not missing and v is not None}
4253+
4254+
retry_strategy = self.base_client.get_preferred_retry_strategy(
4255+
operation_retry_strategy=kwargs.get('retry_strategy'),
4256+
client_retry_strategy=self.retry_strategy
4257+
)
4258+
4259+
if retry_strategy:
4260+
if not isinstance(retry_strategy, retry.NoneRetryStrategy):
4261+
self.base_client.add_opc_retry_token_if_needed(header_params)
4262+
self.base_client.add_opc_client_retries_header(header_params)
4263+
retry_strategy.add_circuit_breaker_callback(self.circuit_breaker_callback)
4264+
return retry_strategy.make_retrying_call(
4265+
self.base_client.call_api,
4266+
resource_path=resource_path,
4267+
method=method,
4268+
path_params=path_params,
4269+
header_params=header_params,
4270+
allow_control_chars=kwargs.get('allow_control_chars'),
4271+
operation_name=operation_name,
4272+
api_reference_link=api_reference_link,
4273+
required_arguments=required_arguments)
4274+
else:
4275+
return self.base_client.call_api(
4276+
resource_path=resource_path,
4277+
method=method,
4278+
path_params=path_params,
4279+
header_params=header_params,
4280+
allow_control_chars=kwargs.get('allow_control_chars'),
4281+
operation_name=operation_name,
4282+
api_reference_link=api_reference_link,
4283+
required_arguments=required_arguments)
4284+
41714285
def convert_to_pdb(self, database_id, convert_to_pdb_details, **kwargs):
41724286
"""
41734287
Converts a non-container database to a pluggable database.

src/oci/database/database_client_composite_operations.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,44 @@ def configure_saas_admin_user_and_wait_for_state(self, autonomous_database_id, c
18401840
except Exception as e:
18411841
raise oci.exceptions.CompositeOperationError(partial_results=[operation_result], cause=e)
18421842

1843+
def confirm_key_store_details_are_correct_and_wait_for_work_request(self, key_store_id, work_request_states=[], operation_kwargs={}, waiter_kwargs={}):
1844+
"""
1845+
Calls :py:func:`~oci.database.DatabaseClient.confirm_key_store_details_are_correct` and waits for the oci.work_requests.models.WorkRequest
1846+
to enter the given state(s).
1847+
1848+
:param str key_store_id: (required)
1849+
The `OCID`__ of the key store.
1850+
1851+
__ https://docs.cloud.oracle.com/Content/General/Concepts/identifiers.htm
1852+
1853+
:param list[str] work_request_states: (optional)
1854+
An array of work requests states to wait on. These should be valid values for :py:attr:`~oci.work_requests.models.WorkRequest.status`
1855+
Default values are termination states: [STATUS_SUCCEEDED, STATUS_FAILED, STATUS_CANCELED]
1856+
1857+
:param dict operation_kwargs:
1858+
A dictionary of keyword arguments to pass to :py:func:`~oci.database.DatabaseClient.confirm_key_store_details_are_correct`
1859+
1860+
:param dict waiter_kwargs:
1861+
A dictionary of keyword arguments to pass to the :py:func:`oci.wait_until` function. For example, you could pass ``max_interval_seconds`` or ``max_interval_seconds``
1862+
as dictionary keys to modify how long the waiter function will wait between retries and the maximum amount of time it will wait
1863+
"""
1864+
operation_result = self.client.confirm_key_store_details_are_correct(key_store_id, **operation_kwargs)
1865+
work_request_states = work_request_states if work_request_states else oci.waiter._WORK_REQUEST_TERMINATION_STATES
1866+
lowered_work_request_states = [w.lower() for w in work_request_states]
1867+
if 'opc-work-request-id' not in operation_result.headers:
1868+
return operation_result
1869+
work_request_id = operation_result.headers['opc-work-request-id']
1870+
try:
1871+
waiter_result = oci.wait_until(
1872+
self._work_request_client,
1873+
self._work_request_client.get_work_request(work_request_id),
1874+
evaluate_response=lambda r: getattr(r.data, 'status') and getattr(r.data, 'status').lower() in lowered_work_request_states,
1875+
**waiter_kwargs
1876+
)
1877+
return waiter_result
1878+
except Exception as e:
1879+
raise oci.exceptions.CompositeOperationError(partial_results=[operation_result], cause=e)
1880+
18431881
def convert_to_pdb_and_wait_for_work_request(self, database_id, convert_to_pdb_details, work_request_states=[], operation_kwargs={}, waiter_kwargs={}):
18441882
"""
18451883
Calls :py:func:`~oci.database.DatabaseClient.convert_to_pdb` and waits for the oci.work_requests.models.WorkRequest

0 commit comments

Comments
 (0)