oracle / oci-python-sdk

Oracle Cloud Infrastructure SDK for Python
https://cloud.oracle.com/cloud-infrastructure
Other
392 stars 281 forks source link

traceback in create_compartment_and_wait_for_state() #474

Open cu opened 2 years ago

cu commented 2 years ago

I am using the oci package version 2.80.0.

I am trying to create a new compartment under my tenancy and decided to try with create_compartment_and_wait_for_state() since compartment creation is apparently not instantaneous.

This is my code:

import oci

config = oci.config.from_file()
identity_client = oci.identity.IdentityClient(config)

id_client_composite = oci.identity.IdentityClientCompositeOperations(identity_client)

comp_details = oci.identity.models.CreateCompartmentDetails()
comp_details.compartment_id = config['tenancy']
comp_details.name = 'example'
comp_details.description = "Example Compartment"

create_comp_response = id_client_composite.create_compartment_and_wait_for_state(
    comp_details,
    [oci.identity.models.Compartment.LIFECYCLE_STATE_ACTIVE]
)

print(create_comp_response.data)

The compartment is actually created, but the call results in a traceback, exiting my script before it can print the results and I'm unable to determine what is wrong. It looks like an exception is being raised because the API is returning a 404 before the compartment is ready, but the whole point of this function is to keep trying anyway until it exists, no?

Full traceback:

ServiceError                              Traceback (most recent call last)
File ~/sandbox/learn-terraform-oci/.venv/lib/python3.10/site-packages/oci/identity/identity_client_composite_operations.py:502, in IdentityClientCompositeOperations.create_compartment_and_wait_for_state(self, create_compartment_details, wait_for_states, operation_kwargs, waiter_kwargs)
    499 try:
    500     waiter_result = oci.wait_until(
    501         self.client,
--> 502         self.client.get_compartment(compartment_id),  # noqa: F821
    503         evaluate_response=lambda r: getattr(r.data, 'lifecycle_state') and getattr(r.data, 'lifecycle_state').lower() in lowered_wait_for_states,
    504         **waiter_kwargs
    505     )
    506     result_to_return = waiter_result

File ~/sandbox/learn-terraform-oci/.venv/lib/python3.10/site-packages/oci/identity/identity_client.py:6570, in IdentityClient.get_compartment(self, compartment_id, **kwargs)
   6569         retry_strategy.add_circuit_breaker_callback(self.circuit_breaker_callback)
-> 6570     return retry_strategy.make_retrying_call(
   6571         self.base_client.call_api,
   6572         resource_path=resource_path,
   6573         method=method,
   6574         path_params=path_params,
   6575         header_params=header_params,
   6576         response_type="Compartment",
   6577         allow_control_chars=kwargs.get('allow_control_chars'),
   6578         operation_name=operation_name,
   6579         api_reference_link=api_reference_link)
   6580 else:

File ~/sandbox/learn-terraform-oci/.venv/lib/python3.10/site-packages/oci/retry/retry.py:308, in ExponentialBackoffRetryStrategyBase.make_retrying_call(self, func_ref, *func_args, **func_kwargs)
    307     _is_body_retryable, body_position = record_body_position_for_rewind(func_kwargs.get('body'))
--> 308 response = func_ref(*func_args, **func_kwargs)
    309 time_elapsed = time.time() - start_time

File ~/sandbox/learn-terraform-oci/.venv/lib/python3.10/site-packages/oci/base_client.py:477, in BaseClient.call_api(self, resource_path, method, path_params, query_params, header_params, body, response_type, enforce_content_headers, allow_control_chars, operation_name, api_reference_link)
    476 start = timer()
--> 477 response = self.request(request, allow_control_chars, operation_name, api_reference_link)
    478 end = timer()

File ~/sandbox/learn-terraform-oci/.venv/lib/python3.10/site-packages/circuitbreaker.py:159, in CircuitBreaker.decorate.<locals>.wrapper(*args, **kwargs)
    158     raise CircuitBreakerError(self)
--> 159 return call(function, *args, **kwargs)

File ~/sandbox/learn-terraform-oci/.venv/lib/python3.10/site-packages/circuitbreaker.py:170, in CircuitBreaker.call(self, func, *args, **kwargs)
    169 with self:
--> 170     return func(*args, **kwargs)

File ~/sandbox/learn-terraform-oci/.venv/lib/python3.10/site-packages/oci/base_client.py:617, in BaseClient.request(self, request, allow_control_chars, operation_name, api_reference_link)
    616     else:
--> 617         self.raise_service_error(request, response, service_code, message, operation_name, api_reference_link, target_service, request_endpoint, client_version, timestamp, deserialized_data)
    619 if stream:
    620     # Don't unpack a streaming response body

File ~/sandbox/learn-terraform-oci/.venv/lib/python3.10/site-packages/oci/base_client.py:774, in BaseClient.raise_service_error(self, request, response, service_code, message, operation_name, api_reference_link, target_service, request_endpoint, client_version, timestamp, deserialized_data)
    773 def raise_service_error(self, request, response, service_code, message, operation_name=None, api_reference_link=None, target_service=None, request_endpoint=None, client_version=None, timestamp=None, deserialized_data=None):
--> 774     raise exceptions.ServiceError(
    775         response.status_code,
    776         service_code,
    777         response.headers,
    778         message,
    779         original_request=request,
    780         operation_name=operation_name,
    781         api_reference_link=api_reference_link,
    782         target_service=target_service,
    783         request_endpoint=request_endpoint,
    784         client_version=client_version,
    785         timestamp=timestamp,
    786         deserialized_data=deserialized_data)

ServiceError: {'target_service': 'identity', 'status': 404, 'code': 'NotAuthorizedOrNotFound', 'opc-request-id': 'A28766893843425385E4AA6B337DE7E1/0F1BD940510D5634C511B74EF8FA104E/D5F7439F36E6B451A36225013507246A', 'message': 'Authorization failed or requested resource not found', 'operation_name': 'get_compartment', 'timestamp': '2022-08-25T01:35:06.144225+00:00', 'client_version': 'Oracle-PythonSDK/2.80.0', 'request_endpoint': 'GET https://identity.us-sanjose-1.oci.oraclecloud.com/20160918/compartments/ocid1.compartment.oc1..aaaaaaaax4qbx5zm5hqueypooy4ofpbryidnvuyqyen5hbc7s5i3ggplpf2a', 'logging_tips': 'To get more info on the failing request, refer to https://docs.oracle.com/en-us/iaas/tools/python/latest/logging.html for ways to log the request/response details.', 'troubleshooting_tips': "See https://docs.oracle.com/iaas/Content/API/References/apierrors.htm#apierrors_404__404_notauthorizedornotfound for more information about resolving this error. Also see https://docs.oracle.com/iaas/api/#/en/identity/20160918/Compartment/GetCompartment for details on this operation's requirements. If you are unable to resolve this identity issue, please contact Oracle support and provide them this full error message."}

During handling of the above exception, another exception occurred:

CompositeOperationError                   Traceback (most recent call last)
Input In [2], in <cell line: 13>()
     10 comp_details.name = 'example'
     11 comp_details.description = "Example Compartment"
---> 13 create_comp_response = id_client_composite.create_compartment_and_wait_for_state(
     14     comp_details,
     15     [oci.identity.models.Compartment.LIFECYCLE_STATE_ACTIVE]
     16 )
     18 print(create_comp_response.data)

File ~/sandbox/learn-terraform-oci/.venv/lib/python3.10/site-packages/oci/identity/identity_client_composite_operations.py:515, in IdentityClientCompositeOperations.create_compartment_and_wait_for_state(self, create_compartment_details, wait_for_states, operation_kwargs, waiter_kwargs)
    513     raise oci.exceptions.CompositeOperationError(partial_results=[operation_result], cause=e)
    514 except Exception as e:
--> 515     raise oci.exceptions.CompositeOperationError(partial_results=[operation_result], cause=e)

CompositeOperationError: 
waruwaruwaru commented 2 years ago

@cu thanks for reporting this issue. The issue is that after creating the compartment and sending back the response, there is a time gap before the compartment actually exists in the identity server. We are aware of this and currently talking with the Identity team to resolve this issue. In the meantime, create_compartment_and_wait_for_state() will not work but a work around can be to call get_compartment and do a retry on 404s that come back. It would take maybe 1 second for the get_compartment request to return a 200