Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion examples/test_resource_controller_v2_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,8 @@ def test_get_resource_binding_example(self):
resource_binding = resource_controller_service.get_resource_binding(
id=binding_guid
).get_result()

if resource_binding.get('credentials') and resource_binding.get('credentials').get('REDACTED'):
print("Credentials are redacted with code:", resource_binding.get('credentials').get('REDACTED'), ".The User doesn't have the correct access to view the credentials. Refer to the API documentation for additional details.")
print(json.dumps(resource_binding, indent=2))

# end-get_resource_binding
Expand Down Expand Up @@ -477,6 +478,8 @@ def test_get_resource_key_example(self):
resource_key = resource_controller_service.get_resource_key(
id=instance_key_guid
).get_result()
if resource_key.get('credentials') and resource_key.get('credentials').get('REDACTED'):
print("Credentials are redacted with code:", resource_key.get('credentials').get('REDACTED'), ".The User doesn't have the correct access to view the credentials. Refer to the API documentation for additional details.")

print(json.dumps(resource_key, indent=2))

Expand Down Expand Up @@ -721,6 +724,28 @@ def test_run_reclamation_action_example(self):
except ApiException as e:
pytest.fail(str(e))

@needscredentials
def test_cancel_lastop_resource_instance_example(self):
"""
cancel_lastop_resource_instance request example
"""
try:
print('\ncancel_lastop_resource_instance() result:')
# begin-cancel_lastop_resource_instance

resource_instance = resource_controller_service.cancel_lastop_resource_instance(
id=instance_guid
).get_result()
print(json.dumps(resource_instance, indent=2))

# end-cancel_lastop_resource_instance

except ApiException as e:
if e.message == "The instance is not cancelable.":
print("The instance is not cancelable")
else:
pytest.fail(str(e))

# endregion
##############################################################################
# End of Examples for Service: ResourceControllerV2
Expand Down
56 changes: 55 additions & 1 deletion ibm_platform_services/resource_controller_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,44 @@ def unlock_resource_instance(self,
response = self.send(request)
return response

def cancel_lastop_resource_instance(self,
id: str,
**kwargs
) -> DetailedResponse:
"""
Cancel the in progress last operation of the resource instance.

Cancel the in progress last operation of the resource instance. After successful
cancellation, the resource instance is removed.

:param str id: The resource instance URL-encoded CRN or GUID.
:param dict headers: A `dict` containing the request headers
:return: A `DetailedResponse` containing the result, headers and HTTP status code.
:rtype: DetailedResponse with `dict` result representing a `ResourceInstance` object
"""

if id is None:
raise ValueError('id must be provided')
headers = {}
sdk_headers = get_sdk_headers(service_name=self.DEFAULT_SERVICE_NAME,
service_version='V2',
operation_id='cancel_lastop_resource_instance')
headers.update(sdk_headers)

if 'headers' in kwargs:
headers.update(kwargs.get('headers'))
headers['Accept'] = 'application/json'

path_param_keys = ['id']
path_param_values = self.encode_path_vars(id)
path_param_dict = dict(zip(path_param_keys, path_param_values))
url = '/v2/resource_instances/{id}/last_operation'.format(**path_param_dict)
request = self.prepare_request(method='DELETE',
url=url,
headers=headers)

response = self.send(request)
return response
#########################
# Resource Keys
#########################
Expand Down Expand Up @@ -1592,6 +1630,11 @@ class Credentials():
"""
The credentials for a resource.

:attr str redacted: (optional) If present, the user doesn't have the correct
access to view the credentials and the details are redacted. The string value
identifies the level of access that's required to view the credential. For
additional information, see [viewing a
credential](https://cloud.ibm.com/docs/account?topic=account-service_credentials&interface=ui#viewing-credentials-ui).
:attr str apikey: (optional) The API key for the credentials.
:attr str iam_apikey_description: (optional) The optional description of the API
key.
Expand All @@ -1603,10 +1646,11 @@ class Credentials():
"""

# The set of defined properties for the class
_properties = frozenset(['apikey', 'iam_apikey_description', 'iam_apikey_name', 'iam_role_crn', 'iam_serviceid_crn'])
_properties = frozenset(['REDACTED', 'apikey', 'iam_apikey_description', 'iam_apikey_name', 'iam_role_crn', 'iam_serviceid_crn'])

def __init__(self,
*,
redacted: str = None,
apikey: str = None,
iam_apikey_description: str = None,
iam_apikey_name: str = None,
Expand All @@ -1616,6 +1660,11 @@ def __init__(self,
"""
Initialize a Credentials object.

:param str redacted: (optional) If present, the user doesn't have the
correct access to view the credentials and the details are redacted. The
string value identifies the level of access that's required to view the
credential. For additional information, see [viewing a
credential](https://cloud.ibm.com/docs/account?topic=account-service_credentials&interface=ui#viewing-credentials-ui).
:param str apikey: (optional) The API key for the credentials.
:param str iam_apikey_description: (optional) The optional description of
the API key.
Expand All @@ -1626,6 +1675,7 @@ def __init__(self,
service ID of the credentials.
:param **kwargs: (optional) Any additional properties.
"""
self.redacted = redacted
self.apikey = apikey
self.iam_apikey_description = iam_apikey_description
self.iam_apikey_name = iam_apikey_name
Expand All @@ -1638,6 +1688,8 @@ def __init__(self,
def from_dict(cls, _dict: Dict) -> 'Credentials':
"""Initialize a Credentials object from a json dictionary."""
args = {}
if 'REDACTED' in _dict:
args['redacted'] = _dict.get('REDACTED')
if 'apikey' in _dict:
args['apikey'] = _dict.get('apikey')
if 'iam_apikey_description' in _dict:
Expand All @@ -1659,6 +1711,8 @@ def _from_dict(cls, _dict):
def to_dict(self) -> Dict:
"""Return a json dictionary representing this model."""
_dict = {}
if hasattr(self, 'redacted') and self.redacted is not None:
_dict['REDACTED'] = self.redacted
if hasattr(self, 'apikey') and self.apikey is not None:
_dict['apikey'] = self.apikey
if hasattr(self, 'iam_apikey_description') and self.iam_apikey_description is not None:
Expand Down
14 changes: 14 additions & 0 deletions test/integration/test_resource_controller_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1292,6 +1292,20 @@ def test_52_reclaim_resource_instance(self):
assert result.get('state') == 'RECLAIMING'

time.sleep(20)

def test_53_cancel_last_operation(self):

customHeaders = {}
customHeaders["Transaction-Id"] = "rc-sdk-python-test53-" + \
self.transactionId
try:
response = self.service.cancel_lastop_resource_instance(
id=self.testInstanceGuid,
headers=customHeaders)
assert response is not None
except ApiException as e:
assert e.message == "The instance is not cancelable."


# Commented because redis timeouts cause intermittent failure

Expand Down
65 changes: 65 additions & 0 deletions test/unit/test_resource_controller_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,71 @@ def test_unlock_resource_instance_value_error(self):
with pytest.raises(ValueError):
_service.unlock_resource_instance(**req_copy)

class TestCancelLastopResourceInstance():
"""
Test Class for cancel_lastop_resource_instance
"""

def preprocess_url(self, request_url: str):
"""
Preprocess the request URL to ensure the mock response will be found.
"""
if re.fullmatch('.*/+', request_url) is None:
return request_url
else:
return re.compile(request_url.rstrip('/') + '/+')
@responses.activate
def test_cancel_lastop_resource_instance_all_params(self):
"""
cancel_lastop_resource_instance()
"""
# Set up mock
url = self.preprocess_url(_base_url + '/v2/resource_instances/testString/last_operation')
mock_response = '{"id": "id", "guid": "guid", "url": "url", "created_at": "2019-01-01T12:00:00.000Z", "updated_at": "2019-01-01T12:00:00.000Z", "deleted_at": "2019-01-01T12:00:00.000Z", "created_by": "created_by", "updated_by": "updated_by", "deleted_by": "deleted_by", "scheduled_reclaim_at": "2019-01-01T12:00:00.000Z", "restored_at": "2019-01-01T12:00:00.000Z", "restored_by": "restored_by", "scheduled_reclaim_by": "scheduled_reclaim_by", "name": "name", "region_id": "region_id", "account_id": "account_id", "reseller_channel_id": "reseller_channel_id", "resource_plan_id": "resource_plan_id", "resource_group_id": "resource_group_id", "resource_group_crn": "resource_group_crn", "target_crn": "target_crn", "parameters": {"mapKey": "anyValue"}, "allow_cleanup": false, "crn": "crn", "state": "active", "type": "type", "sub_type": "sub_type", "resource_id": "resource_id", "dashboard_url": "dashboard_url", "last_operation": {"type": "type", "state": "in progress", "sub_type": "sub_type", "async": true, "description": "description", "reason_code": "reason_code", "poll_after": 10, "cancelable": true, "poll": true}, "resource_aliases_url": "resource_aliases_url", "resource_bindings_url": "resource_bindings_url", "resource_keys_url": "resource_keys_url", "plan_history": [{"resource_plan_id": "resource_plan_id", "start_date": "2019-01-01T12:00:00.000Z", "requestor_id": "requestor_id"}], "migrated": true, "extensions": {"mapKey": "anyValue"}, "controlled_by": "controlled_by", "locked": true}'
responses.add(responses.DELETE,
url,
body=mock_response,
content_type='application/json',
status=200)

# Set up parameter values
id = 'testString'

# Invoke method
response = _service.cancel_lastop_resource_instance(
id,
headers={}
)

# Check for correct operation
assert len(responses.calls) == 1
assert response.status_code == 200

@responses.activate
def test_cancel_lastop_resource_instance_value_error(self):
"""
test_cancel_lastop_resource_instance_value_error()
"""
# Set up mock
url = self.preprocess_url(_base_url + '/v2/resource_instances/testString/last_operation')
mock_response = '{"id": "id", "guid": "guid", "url": "url", "created_at": "2019-01-01T12:00:00.000Z", "updated_at": "2019-01-01T12:00:00.000Z", "deleted_at": "2019-01-01T12:00:00.000Z", "created_by": "created_by", "updated_by": "updated_by", "deleted_by": "deleted_by", "scheduled_reclaim_at": "2019-01-01T12:00:00.000Z", "restored_at": "2019-01-01T12:00:00.000Z", "restored_by": "restored_by", "scheduled_reclaim_by": "scheduled_reclaim_by", "name": "name", "region_id": "region_id", "account_id": "account_id", "reseller_channel_id": "reseller_channel_id", "resource_plan_id": "resource_plan_id", "resource_group_id": "resource_group_id", "resource_group_crn": "resource_group_crn", "target_crn": "target_crn", "parameters": {"mapKey": "anyValue"}, "allow_cleanup": false, "crn": "crn", "state": "active", "type": "type", "sub_type": "sub_type", "resource_id": "resource_id", "dashboard_url": "dashboard_url", "last_operation": {"type": "type", "state": "in progress", "sub_type": "sub_type", "async": true, "description": "description", "reason_code": "reason_code", "poll_after": 10, "cancelable": true, "poll": true}, "resource_aliases_url": "resource_aliases_url", "resource_bindings_url": "resource_bindings_url", "resource_keys_url": "resource_keys_url", "plan_history": [{"resource_plan_id": "resource_plan_id", "start_date": "2019-01-01T12:00:00.000Z", "requestor_id": "requestor_id"}], "migrated": true, "extensions": {"mapKey": "anyValue"}, "controlled_by": "controlled_by", "locked": true}'
responses.add(responses.DELETE,
url,
body=mock_response,
content_type='application/json',
status=200)

# Set up parameter values
id = 'testString'

# Pass in all but one required param and check for a ValueError
req_param_dict = {
"id": id,
}
for param in req_param_dict.keys():
req_copy = {key:val if key is not param else None for (key,val) in req_param_dict.items()}
with pytest.raises(ValueError):
_service.cancel_lastop_resource_instance(**req_copy)


# endregion
Expand Down