def _get_retry_strategy(): retry_strategy_builder = RetryStrategyBuilder(max_attempts_check=True, max_attempts=10, retry_max_wait_between_calls_seconds=30, retry_base_sleep_time_seconds=3, backoff_type=oci.retry.BACKOFF_FULL_JITTER_EQUAL_ON_THROTTLE_VALUE) retry_strategy_builder.add_service_error_check( service_error_retry_config={429: [], 400: ['QuotaExceeded', 'LimitExceeded']}, service_error_retry_on_any_5xx=True) return retry_strategy_builder.get_retry_strategy()
def do_work_hook(self): if 'content_md5' in self.multipart_kwargs: self.multipart_kwargs.pop('content_md5') self.multipart_kwargs['part_size'] = self.part_size ma = PooledMultipartObjectAssembler(self.object_storage_client, self.namespace_name, self.bucket_name, self.object_name, self.object_storage_request_pool, **self.multipart_kwargs) ma.new_upload() # max_attempts retries - with exponential sleep time and a max wait of 60 secs. retry_strategy = RetryStrategyBuilder(retry_max_wait_between_calls_seconds=60).add_max_attempts(self.max_retries)\ .no_total_elapsed_time() \ .add_service_error_check() \ .get_retry_strategy() ma.add_parts_from_file(self.file_path) if self.multipart_part_completion_callback: ma.upload( progress_callback=self.multipart_part_completion_callback) else: ma.upload(retry_strategy=retry_strategy) response = ma.commit() multipart_hash = cli_util.verify_checksum( self.file_path, no_multipart=False, ma=ma) if self.verify_checksum else None return response, multipart_hash
def run_job(self): self.status = SUCCESS self.log_callback.info('Creating image.') self.request_credentials([self.account]) credentials = self.credentials[self.account] config = { 'user': self.oci_user_id, 'key_content': credentials['signing_key'], 'fingerprint': credentials['fingerprint'], 'tenancy': self.tenancy, 'region': self.region } compute_client = ComputeClient(config) compute_composite_client = ComputeClientCompositeOperations( compute_client) object_name = self.status_msg['object_name'] namespace = self.status_msg['namespace'] self.cloud_image_name = self.status_msg['cloud_image_name'] image_source_details = ImageSourceViaObjectStorageTupleDetails( bucket_name=self.bucket, namespace_name=namespace, object_name=object_name, source_image_type=self.image_type, operating_system=self.operating_system, operating_system_version=self.operating_system_version) image_details = CreateImageDetails( compartment_id=self.compartment_id, display_name=self.cloud_image_name, image_source_details=image_source_details, launch_mode=self.launch_mode) retry_strategy = RetryStrategyBuilder( max_attempts=self.max_oci_attempts, service_error_retry_config={ 'service_error_retry_config': { 400: ['LimitExceeded'] } }).get_retry_strategy() response = compute_composite_client.create_image_and_wait_for_state( create_image_details=image_details, wait_for_states=[Image.LIFECYCLE_STATE_AVAILABLE], operation_kwargs={'retry_strategy': retry_strategy}, waiter_kwargs={'max_wait_seconds': self.max_oci_wait_seconds}) self.status_msg['image_id'] = response.data.id self.log_callback.info( 'Created image has ID: {0}.'.format(object_name))
def cleanup_image(self, credentials, image_id): self.log_callback.info( 'Cleaning up image: {0} in region: {1}.'.format( self.cloud_image_name, self.region ) ) config = { 'user': self.oci_user_id, 'key_content': credentials['signing_key'], 'fingerprint': credentials['fingerprint'], 'tenancy': self.tenancy, 'region': self.region } compute_client = ComputeClient(config) compute_composite_client = ComputeClientCompositeOperations( compute_client ) retry_strategy = RetryStrategyBuilder( max_attempts=self.max_oci_attempts, service_error_retry_config={ 'service_error_retry_config': {400: ['LimitExceeded']} } ).get_retry_strategy() try: compute_composite_client.delete_image_and_wait_for_state( image_id=image_id, wait_for_states=[ Image.LIFECYCLE_STATE_DELETED ], operation_kwargs={'retry_strategy': retry_strategy}, waiter_kwargs={'max_wait_seconds': self.max_oci_wait_seconds} ) except Exception as error: msg = 'Failed to cleanup image: {0}'.format(error) self.add_error_msg(msg) self.log_callback.warning(msg)
def _make_raw_request(ctx, target_uri, http_method, request_body, request_headers): # Endpoint doesn't make sense because we're asking someone for a --target-uri. We could also just use the --endpoint parameter but that # feels like an overloading of that concept (which is declared in cli_root) if ctx.obj['endpoint']: raise click.UsageError( 'The --endpoint parameter cannot be specified with this command') # Table output may not make too much sense here because we're also dumping out headers and status code, in addition # to the data if ctx.obj['output'] == 'table': raise click.UsageError( 'The table output format is not supported with this command') if ctx.obj['debug']: six.moves.http_client.HTTPConnection.debuglevel = 1 jmespath_expression = cli_util.get_jmespath_expression_from_context(ctx) # Deliberately a bit open as we can permit an empty string through as an empty request body parsed_request_body = '' if request_body is not None and request_body.strip() != '': request_body_as_dict = cli_util.parse_json_parameter( 'request_body', request_body, 'camelize_keys', False) parsed_request_body = json.dumps(request_body_as_dict) additional_headers = {} if request_headers: additional_headers = cli_util.parse_json_parameter( 'request_headers', request_headers, 'camelize_keys', False) retry_strategy = DEFAULT_RETRY_STRATEGY if ctx.obj['max_attempts']: retry_strategy = RetryStrategyBuilder().add_max_attempts(max_attempts=ctx.obj['max_attempts']) \ .add_total_elapsed_time(total_elapsed_time_seconds=600) \ .add_service_error_check(service_error_retry_config=retry_checkers.RETRYABLE_STATUSES_AND_CODES, service_error_retry_on_any_5xx=True) \ .get_retry_strategy() if ctx.obj['no_retry']: retry_strategy = oci.retry.NoneRetryStrategy() # Make a request and output the results. The retry strategy should make sure that we can ride out # connection errors or timeouts, but its logic around ServiceError will not kick in because that's our # construct and not something which requests raises. # # However, with the spirit of this operation I think that is OK because really we just want to make a # call and then display the result (even if the result of that call is not a 2xx), so even a 4xx or 5xx # would be considered successful from this operation's perspective as it was able to hit a URI and get # a response with cli_util.build_raw_requests_session(ctx) as requests_session: response = retry_strategy.make_retrying_call( requests_session.request, method=http_method, url=target_uri, data=parsed_request_body, headers=additional_headers) result_dict = { 'status': '{} {}'.format(response.status_code, response.reason), 'headers': {key: value for (key, value) in response.headers.items()} } try: dict_from_response_body = response.json() if jmespath_expression: result_dict['data'] = jmespath_expression.search( dict_from_response_body) else: result_dict['data'] = dict_from_response_body except ValueError: # We may not have gotten valid JSON. In that case, do our best and just display something result_dict['data'] = response.text print(cli_util.pretty_print_format(result_dict))