Skip to content

Commit

Permalink
Merge pull request #274 from cloudify-cosmo/resumable
Browse files Browse the repository at this point in the history
Resumable actions support
  • Loading branch information
0lvin committed Jul 4, 2019
2 parents e539306 + fe3d19a commit f7320c3
Show file tree
Hide file tree
Showing 19 changed files with 51 additions and 91 deletions.
38 changes: 20 additions & 18 deletions CHANGELOG.txt
@@ -1,11 +1,11 @@
1.4.2
1.4.2:
- Moved EC2 and VPC to cloudify_aws package
- Added an Instance-Subnet connected_to relationship
1.4.3
1.4.3:
- Add Subnet create retry operation
- Improvements to ELB creation
- Fix bug that delete External Resource keypairs
1.4.4
1.4.4:
- Improve Test Coverage
- Improve function naming
- Support tagging of all types (where available via API)
Expand All @@ -16,39 +16,39 @@
- Support Security Group rules as a node type
- Support resource state verification
- Clearer log messages
1.4.5
- Support Security Group rules creation by ID
- Fix validation errors
1.4.5:
- Support Security Group rules creation by ID
- Fix validation errors
- Fix duplicated mapping key
1.4.6
1.4.6:
- Fix random EIP disassociated
1.4.7
1.4.7:
- Support circular dependency of security groups
1.4.8
1.4.8:
- Support attaching existing volume to instance
1.4.9
1.4.9:
- Add revoke rules from security group retry operation
- Added handling for missing provider_context and missing homedir issues in 4.0.1
1.4.10
1.4.10:
- Add delete security group retry operation
1.4.11
1.4.11:
- Fixed bug that attempt to delete external security group
1.4.12
1.4.12:
- Fixed error message when unlinking route table from gateway
- Support passing runtime properties to create operation
1.4.13
1.4.13:
- Fixed bug that instance get resource returns something when no id was provided
1.5
1.5:
- Associate ElasticIP to resources base on ip property instead of base on resource type
- Fix the need for an operations name to be in the format <something>.<create/start/stop/delete> (Aria Tosca)
- Add connect Security Groups to Instance via InstanceConnectedToSecurityGroup relationship
- Support adding VPC Peering Connection + Use external routes
- Fix bug that disassociate the wrong elastic ip from its instance
1.5.1
1.5.1:
- Support Windows instances with init_script agent installation method.
1.5.1.1
1.5.1.1:
- Fix bug when init_script is empty string.
1.5.1.2
1.5.1.2:
- Execute user-provided user data before agent install user data.
2.0.0:
- Update aws plugin node types
Expand All @@ -61,3 +61,5 @@
- Support multiple subnet attachments to network acl.
2.1.0:
- Make Resource Naming Resolution consistent across the plugin.
2.2.0:
- Add resumable support to operations
3 changes: 0 additions & 3 deletions cloudify_aws/autoscaling/resources/launch_configuration.py
Expand Up @@ -62,9 +62,6 @@ def properties(self):
@property
def status(self):
"""Gets the status of an external resource"""
props = self.properties
if not props:
return None
return None

def create(self, params):
Expand Down
3 changes: 0 additions & 3 deletions cloudify_aws/autoscaling/resources/lifecycle_hook.py
Expand Up @@ -53,9 +53,6 @@ def properties(self):
@property
def status(self):
"""Gets the status of an external resource"""
props = self.properties
if not props:
return None
return None

def create(self, params):
Expand Down
3 changes: 0 additions & 3 deletions cloudify_aws/autoscaling/resources/policy.py
Expand Up @@ -55,9 +55,6 @@ def properties(self):
@property
def status(self):
"""Gets the status of an external resource"""
props = self.properties
if not props:
return None
return None

def create(self, params):
Expand Down
3 changes: 0 additions & 3 deletions cloudify_aws/cloudwatch/resources/alarm.py
Expand Up @@ -51,9 +51,6 @@ def properties(self):
@property
def status(self):
"""Gets the status of an external resource"""
props = self.properties
if not props:
return None
return None

def create(self, params):
Expand Down
3 changes: 0 additions & 3 deletions cloudify_aws/cloudwatch/resources/rule.py
Expand Up @@ -56,9 +56,6 @@ def properties(self):
@property
def status(self):
"""Gets the status of an external resource"""
props = self.properties
if not props:
return None
return None

def create(self, params):
Expand Down
8 changes: 0 additions & 8 deletions cloudify_aws/cloudwatch/tests/test_alarm.py
Expand Up @@ -192,10 +192,6 @@ def test_CloudwatchAlarmClass_status(self):

self.assertEqual(test_instance.status, None)

self.fake_client.describe_alarms.assert_called_with(
AlarmNames=['alarm_id']
)

def test_CloudwatchAlarmClass_status_empty(self):
test_instance = alarm.CloudwatchAlarm("ctx_node",
resource_id='alarm_id',
Expand All @@ -204,10 +200,6 @@ def test_CloudwatchAlarmClass_status_empty(self):

self.assertEqual(test_instance.status, None)

self.fake_client.describe_alarms.assert_called_with(
AlarmNames=['alarm_id']
)


if __name__ == '__main__':
unittest.main()
8 changes: 0 additions & 8 deletions cloudify_aws/cloudwatch/tests/test_rule.py
Expand Up @@ -174,10 +174,6 @@ def test_CloudwatchEventsRuleClass_status(self):

self.assertEqual(test_instance.status, None)

self.fake_client.describe_rule.assert_called_with(
Name=['rule_id']
)

def test_CloudwatchEventsRuleClass_status_empty(self):
test_instance = rule.CloudwatchEventsRule("ctx_node",
resource_id='rule_id',
Expand All @@ -186,10 +182,6 @@ def test_CloudwatchEventsRuleClass_status_empty(self):

self.assertEqual(test_instance.status, None)

self.fake_client.describe_rule.assert_called_with(
Name=['rule_id']
)


if __name__ == '__main__':
unittest.main()
21 changes: 12 additions & 9 deletions cloudify_aws/common/decorators.py
Expand Up @@ -22,6 +22,7 @@
import sys

# Third party imports
from cloudify.decorators import operation
from cloudify.exceptions import (OperationRetry, NonRecoverableError)
from cloudify.utils import exception_to_error_cause
from botocore.exceptions import ClientError
Expand Down Expand Up @@ -84,7 +85,7 @@ def wrapper_inner(**kwargs):
ctx.target.instance.runtime_properties._set_changed()
return ret
return wrapper_inner
return wrapper_outer
return operation(func=wrapper_outer, resumable=True)


def aws_params(resource_name, params_priority=True):
Expand Down Expand Up @@ -245,9 +246,15 @@ def wrapper_inner(**kwargs):
return
ctx.logger.warn('%s ID# "%s" has force_operation set.'
% (resource_type, resource_id))
return function(**kwargs)
result = function(**kwargs)
if ctx.operation.name == 'cloudify.interfaces.lifecycle.delete':
# cleanup runtime after delete
keys = ctx.instance.runtime_properties.keys()
for key in keys:
del ctx.instance.runtime_properties[key]
return result
return wrapper_inner
return wrapper_outer
return operation(func=wrapper_outer, resumable=True)


def wait_for_status(status_good=None,
Expand Down Expand Up @@ -280,11 +287,6 @@ def wrapper_inner(**kwargs):
# so updating iface object
iface.resource_id = \
ctx.instance.runtime_properties.get(EXT_RES_ID)
# If sequence of install -> uninstall workflows was
# executed, we should remove '__deleted'
# flag set in the decorator wait_for_delete below
if '__deleted' in ctx.instance.runtime_properties:
del ctx.instance.runtime_properties['__deleted']

# Get a resource interface and query for the status
status = iface.status
Expand Down Expand Up @@ -324,6 +326,7 @@ def wrapper_inner(**kwargs):
# Run the operation if this is the first pass
if not ctx.instance.runtime_properties.get('__deleted', False):
function(**kwargs)
# flag will be removed after first call without any exceptions
ctx.instance.runtime_properties['__deleted'] = True
# Get a resource interface and query for the status
status = iface.status
Expand Down Expand Up @@ -408,7 +411,7 @@ def wrapper(**kwargs):
return response

return func(**kwargs)
return wrapper
return operation(func=wrapper, resumable=True)


def tag_resources(fn):
Expand Down
13 changes: 13 additions & 0 deletions cloudify_aws/common/tests/test_decorators.py
Expand Up @@ -363,6 +363,19 @@ def test_func(*agrs, **kwargs):
'aws_resource_id': 'res_id',
'resource_config': {}})

# run delete operation
_ctx = self._gen_decorators_context('test_aws_resource', runtime_prop={
'aws_resource_arn': 'res_arn',
'resource_config': {}
})
_operation = MagicMock()
_operation.name = 'cloudify.interfaces.lifecycle.delete'
_ctx._operation = _operation
test_func(ctx=_ctx, aws_resource_id='res_id')

self.assertEqual(_ctx.instance.runtime_properties,
{})

def test_aws_resource_update_resource_arn(self):

fake_class_instance = MagicMock()
Expand Down
4 changes: 2 additions & 2 deletions cloudify_aws/dynamodb/resources/table.py
Expand Up @@ -51,8 +51,8 @@ def properties(self):
def status(self):
"""Gets the status of an external resource"""
props = self.properties
if props and 'TableStatus' in props:
return props['TableStatus']
if props:
return props.get('TableStatus')
return None

def create(self, params):
Expand Down
8 changes: 0 additions & 8 deletions cloudify_aws/ec2/resources/eni.py
Expand Up @@ -201,14 +201,6 @@ def delete(ctx, iface, resource_config, **_):
ctx.instance.runtime_properties.get(EXTERNAL_RESOURCE_ID)

iface.delete(params)
for prop in ['resource_config',
'aws_resource_id',
'device_index',
'create_response']:
try:
del ctx.instance.runtime_properties[prop]
except KeyError:
pass


@decorators.aws_resource(EC2NetworkInterface, RESOURCE_TYPE)
Expand Down
8 changes: 0 additions & 8 deletions cloudify_aws/ec2/resources/instances.py
Expand Up @@ -365,14 +365,6 @@ def delete(iface, resource_config, **_):
params = \
dict() if not resource_config else resource_config.copy()
iface.delete({INSTANCE_IDS: params.get(INSTANCE_IDS, [iface.resource_id])})
for prop in ['ip',
'private_ip_address',
'public_ip_address',
'create_response']:
try:
del ctx.instance.runtime_properties[prop]
except KeyError:
pass


@decorators.aws_resource(EC2Instances, RESOURCE_TYPE)
Expand Down
3 changes: 0 additions & 3 deletions cloudify_aws/ec2/resources/keypair.py
Expand Up @@ -177,9 +177,6 @@ def delete(iface, resource_config, **_):

iface.delete({KEYNAME: key_name})

if ctx.node.properties['store_in_runtime_properties']:
del ctx.instance.runtime_properties['create_response']

if ctx.node.properties['create_secret']:
try:
client = get_rest_client()
Expand Down
2 changes: 1 addition & 1 deletion cloudify_aws/ec2/resources/routetable.py
Expand Up @@ -173,7 +173,7 @@ def attach(ctx, iface, resource_config, **_):
subnet_id or \
targ.target.instance.runtime_properties.get(EXTERNAL_RESOURCE_ID)

# # Actually attach the resources
# Actually attach the resources
association_id_list = iface.attach(params)
association_id = association_id_list.get(ASSOCIATION_ID)
ctx.instance.runtime_properties['association_id'] = association_id
Expand Down
7 changes: 0 additions & 7 deletions cloudify_aws/ec2/resources/securitygroup.py
Expand Up @@ -182,13 +182,6 @@ def delete(ctx, iface, resource_config, **_):
group_id = iface.resource_id

iface.delete({GROUPID: group_id})
for prop in ['resource_config',
'aws_resource_id',
'create_response']:
try:
del ctx.instance.runtime_properties[prop]
except KeyError:
pass


@decorators.aws_resource(EC2SecurityGroup, RESOURCE_TYPE)
Expand Down
1 change: 0 additions & 1 deletion cloudify_aws/ec2/resources/vpn_gateway.py
Expand Up @@ -116,7 +116,6 @@ def create(ctx, iface, resource_config, **_):
params = \
dict() if not resource_config else resource_config.copy()

# Actually create the resource
# Actually create the resource
create_response = iface.create(params)['VpnGateway']
ctx.instance.runtime_properties['create_response'] = \
Expand Down
4 changes: 2 additions & 2 deletions plugin.yaml
Expand Up @@ -2,9 +2,9 @@ plugins:

aws:
executor: central_deployment_agent
source: https://github.com/cloudify-cosmo/cloudify-aws-plugin/archive/2.1.0.zip
source: https://github.com/cloudify-cosmo/cloudify-aws-plugin/archive/2.2.0.zip
package_name: cloudify-aws-plugin
package_version: '2.1.0'
package_version: '2.2.0'

data_types:

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -19,7 +19,7 @@

setup(
name='cloudify-aws-plugin',
version='2.1.0',
version='2.2.0',
author='Cloudify Platform Ltd.',
author_email='hello@cloudify.co',
license='LICENSE',
Expand Down

0 comments on commit f7320c3

Please sign in to comment.