Fix a regression for CustomTimeouts in Python SDK (#3964)

* Fix a regression for CustomTimeouts in Python SDK
* Accept dict as well as CustomTimeouts object
This commit is contained in:
Lee Zen 2020-02-22 19:32:06 -08:00 committed by GitHub
parent 24a1cc433a
commit 33b232adc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 74 additions and 51 deletions

View file

@ -1,6 +1,9 @@
CHANGELOG
=========
- Fix a regression for CustomTimeouts in Python SDK
[#3964](https://github.com/pulumi/pulumi/pull/3964)
## 1.11.0 (2020-02-19)
- Allow oversize protocol buffers for Python SDK.
[#3895](https://github.com/pulumi/pulumi/pull/3895)

View file

@ -31,6 +31,7 @@ if TYPE_CHECKING:
@known_types.custom_timeouts
class CustomTimeouts:
create: Optional[str]
"""

View file

@ -35,6 +35,9 @@ from typing import Any, Optional
_custom_resource_type: Optional[type] = None
"""The type of CustomResource. Filled-in as the Pulumi package is initializing."""
_custom_timeouts_type: Optional[type] = None
"""The type of CustomTimeouts. Filled-in as the Pulumi package is initializing."""
_asset_resource_type: Optional[type] = None
"""The type of Asset. Filled-in as the Pulumi package is initializing."""
@ -166,6 +169,16 @@ def custom_resource(class_obj: type) -> type:
_custom_resource_type = class_obj
return class_obj
def custom_timeouts(class_obj: type) -> type:
"""
Decorator to annotate the CustomTimeouts class. Registers the decorated class
as the CustomTimeouts known type.
"""
assert isinstance(class_obj, type), "class_obj is not a Class"
global _custom_timeouts_type
_custom_timeouts_type = class_obj
return class_obj
def stack(class_obj: type) -> type:
"""
Decorator to annotate the Stack class. Registers the decorated class
@ -267,6 +280,12 @@ def is_custom_resource(obj: Any) -> bool:
"""
return _custom_resource_type is not None and isinstance(obj, _custom_resource_type)
def is_custom_timeouts(obj: Any) -> bool:
"""
Returns true if the given type is a CustomTimeouts, false otherwise.
"""
return _custom_timeouts_type is not None and isinstance(obj, _custom_timeouts_type)
def is_stack(obj: Any) -> bool:
"""
Returns true if the given type is an Output, false otherwise.

View file

@ -343,16 +343,28 @@ def register_resource(res: 'Resource', ty: str, name: str, custom: bool, props:
additional_secret_outputs = map(
res.translate_input_property, opts.additional_secret_outputs)
# translate the CustomTimeouts object
# Translate the CustomTimeouts object.
custom_timeouts = None
if opts.custom_timeouts is not None:
custom_timeouts = resource_pb2.RegisterResourceRequest.CustomTimeouts()
if opts.custom_timeouts.create is not None:
custom_timeouts.create = opts.custom_timeouts.create
if opts.custom_timeouts.update is not None:
custom_timeouts.update = opts.custom_timeouts.update
if opts.custom_timeouts.delete is not None:
custom_timeouts.delete = opts.custom_timeouts.delete
# It could be an actual CustomTimeouts object.
if known_types.is_custom_timeouts(opts.custom_timeouts):
if opts.custom_timeouts.create is not None:
custom_timeouts.create = opts.custom_timeouts.create
if opts.custom_timeouts.update is not None:
custom_timeouts.update = opts.custom_timeouts.update
if opts.custom_timeouts.delete is not None:
custom_timeouts.delete = opts.custom_timeouts.delete
# Or, it could be a workaround passing in a dict.
elif isinstance(opts.custom_timeouts, dict):
if 'create' in opts.custom_timeouts:
custom_timeouts.create = opts.custom_timeouts['create']
if 'update' in opts.custom_timeouts:
custom_timeouts.update = opts.custom_timeouts['update']
if 'delete' in opts.custom_timeouts:
custom_timeouts.delete = opts.custom_timeouts['delete']
else:
raise Exception("Expected custom_timeouts to be a CustomTimeouts object")
req = resource_pb2.RegisterResourceRequest(
type=ty,

View file

@ -9,25 +9,23 @@ import (
func TestCustomTimeouts(t *testing.T) {
opts := &integration.ProgramTestOptions{
Dir: filepath.Join(".", "python"),
Dir: filepath.Join(".", "python", "success"),
Dependencies: []string{
filepath.Join("..", "..", "..", "sdk", "python", "env", "src"),
},
Quick: true,
EditDirs: []integration.EditDir{
{
Dir: "step1",
Additive: true,
},
{
Dir: "step2",
Additive: true,
},
{
Dir: "step3",
Additive: true,
},
Quick: true,
NoParallel: true,
}
integration.ProgramTest(t, opts)
opts = &integration.ProgramTestOptions{
Dir: filepath.Join(".", "python", "failure"),
Dependencies: []string{
filepath.Join("..", "..", "..", "sdk", "python", "env", "src"),
},
Quick: true,
NoParallel: true,
ExpectFailure: true,
}
integration.ProgramTest(t, opts)
}

View file

@ -7,7 +7,7 @@ class Resource1(ComponentResource):
def __init__(self, name, opts=None):
super().__init__("my:module:Resource", name, None, opts)
# Attempt to create a resource with a CustomTimeout
res1 = Resource1("res1",
opts=ResourceOptions(custom_timeouts=CustomTimeouts(create='30m'))
# Attempt to create a resource with a CustomTimeout that should fail
res5 = Resource1("res5",
opts=ResourceOptions(custom_timeouts='asdf')
)

View file

@ -1,13 +0,0 @@
# Copyright 2016-2018, Pulumi Corporation. All rights reserved.
from pulumi import ComponentResource, Resource, ResourceOptions
from pulumi.resource import CustomTimeouts
class Resource1(ComponentResource):
def __init__(self, name, opts=None):
super().__init__("my:module:Resource", name, None, opts)
# Attempt to create a resource with a CustomTimeout
res3 = Resource1("res3",
opts=ResourceOptions(custom_timeouts=CustomTimeouts(delete='30m'))
)

View file

@ -1,13 +0,0 @@
# Copyright 2016-2018, Pulumi Corporation. All rights reserved.
from pulumi import ComponentResource, Resource, ResourceOptions
from pulumi.resource import CustomTimeouts
class Resource1(ComponentResource):
def __init__(self, name, opts=None):
super().__init__("my:module:Resource", name, None, opts)
# Attempt to create a resource with a CustomTimeout
res1 = Resource1("res1",
opts=ResourceOptions(custom_timeouts=CustomTimeouts(create='30m', delete='15m'))
)

View file

@ -0,0 +1,3 @@
name: custom_timeouts
description: A program that instantiates a resource with a custom timeout
runtime: python

View file

@ -8,6 +8,19 @@ class Resource1(ComponentResource):
super().__init__("my:module:Resource", name, None, opts)
# Attempt to create a resource with a CustomTimeout
res1 = Resource1("res1",
opts=ResourceOptions(custom_timeouts=CustomTimeouts(create='30m'))
)
# Also use the previous workaround method, which we should not regress upon
res2 = Resource1("res2",
opts=ResourceOptions(custom_timeouts={'create': '15m', 'delete': '15m'})
)
res3 = Resource1("res3",
opts=ResourceOptions(custom_timeouts=CustomTimeouts(update='30m'))
)
res4 = Resource1("res4",
opts=ResourceOptions(custom_timeouts=CustomTimeouts(delete='30m'))
)