diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 7424fe72f5..adec9c6367 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -3,6 +3,14 @@ Change Log
All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog `_.
+====================
+2.23.3 - 2020-10-29
+====================
+
+Fixed
+-------
+* Fixed an issue where `UploadManager.upload_stream()` raised `MultipartUploadError` if the time to upload is greater than the read timeout. Please see `github issue #300 `_ for more details.
+
====================
2.23.2 - 2020-10-27
====================
diff --git a/docs/known-issues.rst b/docs/known-issues.rst
index 6e7777da5f..bb1361a61c 100644
--- a/docs/known-issues.rst
+++ b/docs/known-issues.rst
@@ -4,9 +4,20 @@ Known Issues
~~~~~~~~~~~~~~~~~~~~~~
These are the current known issues for the Python SDK.
+UploadManager.upload_stream() raises MultipartUploadError in oci v2.23.2
+========================================================================
+`UploadManager.upload_stream() `_ raises MultipartUploadError when a timeout is set on the underlying object storage client, and the operation takes more than the read timeout to complete. Prior to v2.23.2, we were overwriting the timeout to None in the operations (please see this `known issue `_). The default timeout is a read timeout of 60 seconds, hence this scenario will be triggered by default in v2.23.2 on any use of this operation where the operation takes 60 or more seconds to complete.
+You can work around the issue by explicitly setting the timeout to None. For example,
+
+.. code-block:: python
+
+ client.base_client.timeout = None
+
+This issue has been fixed in oci v2.23.3
+
UploadManager generates ssl3_write_pending error when a read timeout is set for the Object Storage client
=========================================================================================================
-**Update:** This issue has been fixed in v2.23.2. This issue still may exist with using Python versions < 2.7.9. If you do encounter this issue, please consult the workaround mentioned below.
+**Update:** This issue has partially been fixed in v2.23.2. This issue still may exist with using Python versions < 2.7.9. If you do encounter this issue, please consult the workaround mentioned below.
**Update:** With v2.18.0 we handle the object storage client with default timeout values (connect timeout = 10 secs and read timeout = 60 secs), by overwriting the timeout to `None` in the operations.
diff --git a/examples/load_balancer_ssl_example.py b/examples/load_balancer_ssl_example.py
new file mode 100644
index 0000000000..c76e17579a
--- /dev/null
+++ b/examples/load_balancer_ssl_example.py
@@ -0,0 +1,177 @@
+# coding: utf-8
+# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
+# This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
+
+# This example creates a new loadbalancer with SSL cipher suites. After that it creates a new listener with the SSL configuration and updates the backend set with it. Finally it updates the loadbalancer cipher suites and deletes it in the end.
+
+import oci
+import argparse
+
+# ---------- parse arguments
+parser = argparse.ArgumentParser()
+parser.add_argument('--compartment-id',
+ help='compartment ID in which to perform the operation',
+ required=True
+ )
+parser.add_argument('--subnet-id',
+ help='subnet ID in which the load balancer will be created',
+ required=True
+ )
+parser.add_argument('--display-name',
+ help='display name for the load balancer to be created',
+ required=False,
+ default='python-sdk-create-lb-example'
+ )
+parser.add_argument('--shape-name',
+ help='shape name of the load balancer to be created',
+ required=False,
+ default='100Mbps'
+ )
+args = parser.parse_args()
+
+# ---------- certificate keys
+cert_private_key = """-----BEGIN RSA PRIVATE KEY-----### the content of your private key ###-----END RSA PRIVATE KEY-----"""
+cert_public_key = """-----BEGIN CERTIFICATE-----### the content of your certificate ###-----END CERTIFICATE-----"""
+cert_password = "password of your certificate"
+
+# ---------- assign provided arguments
+compartment_id = args.compartment_id
+subnet_id = args.subnet_id
+display_name = args.display_name
+shape_name = args.shape_name
+
+# ---------- read config from file
+config = oci.config.from_file()
+load_balancer_client = oci.load_balancer.LoadBalancerClient(config)
+load_balancer_client_composite_ops = oci.load_balancer.LoadBalancerClientCompositeOperations(load_balancer_client)
+
+print('Create new Load Balancer')
+print('\n================================\n')
+# ---------- create load balancer
+load_balancer = load_balancer_client_composite_ops.create_load_balancer_and_wait_for_state(
+ oci.load_balancer.models.CreateLoadBalancerDetails(
+ compartment_id=compartment_id,
+ display_name=display_name,
+ shape_name=shape_name,
+ subnet_ids=[subnet_id],
+ backend_sets={
+ 'backend1': oci.load_balancer.models.BackendSetDetails(
+ policy='ROUND_ROBIN',
+ health_checker=oci.load_balancer.models.HealthCheckerDetails(
+ protocol='HTTP',
+ url_path='/',
+ port=80,
+ retries=1,
+ timeout_in_millis=100,
+ interval_in_millis=1000
+ ),
+ session_persistence_configuration=oci.load_balancer.models.SessionPersistenceConfigurationDetails(
+ cookie_name='*',
+ disable_fallback=False
+ )
+ ),
+ 'backend2': oci.load_balancer.models.BackendSetDetails(
+ policy='ROUND_ROBIN',
+ health_checker=oci.load_balancer.models.HealthCheckerDetails(
+ protocol='HTTP',
+ url_path='/testurl2',
+ port=80,
+ retries=1,
+ timeout_in_millis=100,
+ interval_in_millis=1000
+ )
+ )
+ },
+ ssl_cipher_suites={
+ 'test-suite': oci.load_balancer.models.SSLCipherSuiteDetails(
+ name='test-suite',
+ ciphers=["ECDHE-RSA-AES256-GCM-SHA384", "ECDHE-ECDSA-AES256-GCM-SHA384", "ECDHE-RSA-AES128-GCM-SHA256"]
+ )
+ }
+
+ ),
+ [oci.load_balancer.models.WorkRequest.LIFECYCLE_STATE_SUCCEEDED]
+)
+
+load_balancer_ocid = load_balancer.data.id
+
+print('Created Load Balancer %s' % (load_balancer_ocid))
+print('\n================================\n')
+
+print('Create new certificate')
+print('\n================================\n')
+load_balancer_client_composite_ops.create_certificate_and_wait_for_state(
+ oci.load_balancer.models.CreateCertificateDetails(
+ certificate_name='example-certificate',
+ public_certificate=cert_public_key,
+ passphrase=cert_password,
+ private_key=cert_private_key,
+ ca_certificate=cert_public_key
+ ),
+ load_balancer_ocid,
+ wait_for_states=[oci.load_balancer.models.WorkRequest.LIFECYCLE_STATE_SUCCEEDED]
+)
+
+print('Create new listener with ssl configuration')
+print('\n================================\n')
+load_balancer_client_composite_ops.create_listener_and_wait_for_state(
+ oci.load_balancer.models.CreateListenerDetails(
+ name='listener1',
+ default_backend_set_name='backend1',
+ port=8080,
+ protocol='HTTP',
+ ssl_configuration=oci.load_balancer.models.SSLConfigurationDetails(
+ certificate_name='example-certificate',
+ cipher_suite_name='test-suite',
+ protocols=["TLSv1.1", "TLSv1.2"],
+ server_order_preference="ENABLED",
+ verify_peer_certificate=True
+ )
+ ),
+ load_balancer_ocid,
+ wait_for_states=[oci.load_balancer.models.WorkRequest.LIFECYCLE_STATE_SUCCEEDED]
+)
+
+print('Update backend sets with sslconfig')
+print('\n================================\n')
+load_balancer_client_composite_ops.update_backend_set_and_wait_for_state(
+ oci.load_balancer.models.UpdateBackendSetDetails(
+ policy='ROUND_ROBIN',
+ health_checker=oci.load_balancer.models.HealthCheckerDetails(
+ protocol='HTTP',
+ url_path='/testurl2',
+ port=80,
+ retries=1,
+ timeout_in_millis=100,
+ interval_in_millis=1000
+ ),
+ ssl_configuration=oci.load_balancer.models.SSLConfigurationDetails(
+ certificate_name='example-certificate',
+ cipher_suite_name='test-suite',
+ protocols=["TLSv1.1"],
+ verify_peer_certificate=False
+ ),
+ backends=[]
+ ),
+ load_balancer_ocid,
+ 'backend1',
+ wait_for_states=[oci.load_balancer.models.WorkRequest.LIFECYCLE_STATE_SUCCEEDED]
+)
+
+print('Update ssl cipher suite')
+print('\n================================\n')
+load_balancer_client_composite_ops.update_ssl_cipher_suite_and_wait_for_state(
+ oci.load_balancer.models.UpdateSSLCipherSuiteDetails(
+ ciphers=["DHE-DSS-AES256-SHA256", "CAMELLIA256-SHA"]
+ ),
+ load_balancer_ocid,
+ 'test-suite',
+ wait_for_states=[oci.load_balancer.models.WorkRequest.LIFECYCLE_STATE_SUCCEEDED]
+)
+
+print("Attempting to delete load balancer {}".format(load_balancer_ocid))
+print('\n================================\n')
+load_balancer_client_composite_ops.delete_load_balancer_and_wait_for_state(
+ load_balancer_ocid,
+ wait_for_states=[oci.load_balancer.models.WorkRequest.LIFECYCLE_STATE_SUCCEEDED])
+print('Deleted Load Balancer')
diff --git a/src/oci/object_storage/transfer/internal/multipart_object_assembler.py b/src/oci/object_storage/transfer/internal/multipart_object_assembler.py
index 1c6752a17a..7703a9d639 100644
--- a/src/oci/object_storage/transfer/internal/multipart_object_assembler.py
+++ b/src/oci/object_storage/transfer/internal/multipart_object_assembler.py
@@ -482,7 +482,7 @@ def _upload_stream_part(self, part_num, part_bytes, **kwargs):
self.manifest["objectName"],
self.manifest["uploadId"],
part_num + 1, # Internally this is 0-based but object storage is 1-based
- part_bytes,
+ io.BytesIO(part_bytes),
**new_kwargs
)
except Exception as e:
diff --git a/src/oci/regions.py b/src/oci/regions.py
index 7bde383c15..68c259be9c 100644
--- a/src/oci/regions.py
+++ b/src/oci/regions.py
@@ -21,6 +21,7 @@
'sjc': 'us-sanjose-1',
'fra': 'eu-frankfurt-1',
'zrh': 'eu-zurich-1',
+ 'cwl': 'uk-cardiff-1',
'lhr': 'uk-london-1',
'yyz': 'ca-toronto-1',
'nrt': 'ap-tokyo-1',
@@ -57,6 +58,7 @@
'eu-zurich-1': 'oc1',
'me-dubai-1': 'oc1',
'me-jeddah-1': 'oc1',
+ 'uk-cardiff-1': 'oc1',
'uk-london-1': 'oc1',
'ca-toronto-1': 'oc1',
'sa-saopaulo-1': 'oc1',
@@ -99,6 +101,7 @@
"eu-zurich-1",
"me-dubai-1",
"me-jeddah-1",
+ "uk-cardiff-1",
"uk-london-1",
"uk-gov-cardiff-1",
"ca-toronto-1",
diff --git a/src/oci/version.py b/src/oci/version.py
index c60ce724fa..cf2e743caa 100644
--- a/src/oci/version.py
+++ b/src/oci/version.py
@@ -2,4 +2,4 @@
# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
# This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
-__version__ = "2.23.2"
+__version__ = "2.23.3"