Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Custom Resources to allow configuring timeouts and secrets #1795

Merged
merged 4 commits into from
Nov 5, 2024

Conversation

flostadler
Copy link
Contributor

@flostadler flostadler commented Nov 4, 2024

Previously it was assumed that the custom resources do not concern themselves with secretness or handle timeouts.
But this is necessary to support CloudFormation based Custom Resources.
Those can contain secret outputs and support configuring timeouts.

This change modifies the CustomResource interface to accommodate those requirements.
In detail this means that the Create/Update/Read lifecycle methods now returns a PropertyMap instead of a generic map[string]interface{} and take a timeout
parameter.

For reviewing this change, I'd first recommend having a look at the changes to the CustomResource interface in provider/pkg/resources/custom.go and then double check the refactoring changes resulting in that.

This change also introduces tests for the provider's CRUD lifecycle. As part of doing that, I added mocks using uber/gomock.

Relates to pulumi/pulumi-cdk#109

Previously it was assumed that the custom resources do not concern
themselves with secretness or handle timeouts.
But this is necessary to support CloudFormation based Custom Resources.
Those can contain secret outputs and support configuring timeouts.

This change modifies the `CustomResource` interface to accomomdate
those requirements. In detail this means that the
Create/Update/Read lifecycle methods now returns a `PropertyMap`
instead of a generic `map[string]interface{}` and take a timeout
parameter.
Copy link
Contributor

github-actions bot commented Nov 4, 2024

Does the PR have any schema changes?

Looking good! No breaking changes found.
No new resources/functions.

@flostadler flostadler self-assigned this Nov 4, 2024
Copy link

codecov bot commented Nov 4, 2024

Codecov Report

Attention: Patch coverage is 82.31293% with 26 lines in your changes missing coverage. Please review.

Project coverage is 45.36%. Comparing base (0166a63) to head (30e4e3b).
Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
provider/pkg/resources/extension_resource.go 0.00% 10 Missing ⚠️
provider/pkg/resources/mock_custom_resource.go 81.48% 10 Missing ⚠️
provider/pkg/provider/provider.go 80.64% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1795      +/-   ##
==========================================
+ Coverage   41.17%   45.36%   +4.18%     
==========================================
  Files          35       38       +3     
  Lines        5775     5879     +104     
==========================================
+ Hits         2378     2667     +289     
+ Misses       3187     2989     -198     
- Partials      210      223      +13     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@flostadler
Copy link
Contributor Author

The test coverage of the touched files is mostly through integration tests. I'll try to add some more tests to cover parts of this with units as well

Copy link
Contributor

@corymhall corymhall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this change have any user facing impact, or is it purely internal?

@flostadler
Copy link
Contributor Author

Does this change have any user facing impact, or is it purely internal?

This is purely internal

var createErr error
var payload map[string]interface{}
timeout := time.Duration(req.GetTimeout()) * time.Second
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike bridged providers, guessing there is no need to merge with schema-derived timeouts here?

Also, double-checking, this will be 0 if req.GetTimeout() is unset?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, there's no notion of passing timeouts to the CloudControl based resources (yet).

At the current time no resource is using timeouts yet. This is just prep for the next changes related to CFN CustomResources

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And yes, this will be 0 if no timeouts were specified

// checkpointObject puts inputs in the `__inputs` field of the state.
func checkpointObject(inputs resource.PropertyMap, outputs map[string]interface{}) resource.PropertyMap {
object := resource.NewPropertyMapFromMap(outputs)
object["__inputs"] = resource.MakeSecret(resource.NewObjectProperty(inputs))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a fairly interesting quirk.

"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
)

// CheckpointObject puts inputs in the `__inputs` field of the state.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope here but I am curious now do we understand why it's needed? Throwing a sentence on why we're doing this could be interesting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was done to make diff/read more robust (#17) and solve this issue: #16.

In detail, having access to the old inputs during Read.
I'll put this in the docs in a separate PR

// Read returns the outputs and the updated inputs of the resource.
Read(ctx context.Context, urn resource.URN, id string, oldInputs, oldOutputs resource.PropertyMap) (outputs map[string]any, inputs resource.PropertyMap, exists bool, err error)
Read(ctx context.Context, urn resource.URN, id string, oldInputs, oldOutputs resource.PropertyMap) (outputs resource.PropertyMap, inputs resource.PropertyMap, exists bool, err error)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love a little more type-safety here.

@@ -12,11 +13,11 @@ type CustomResource interface {
// Check validates and transforms the inputs of the resource.
Check(ctx context.Context, urn resource.URN, randomSeed []byte, inputs, state resource.PropertyMap, defaultTags map[string]string) (resource.PropertyMap, []ValidationFailure, error)
// Create creates a new resource in the cloud provider and returns its unique identifier and outputs.
Create(ctx context.Context, urn resource.URN, inputs resource.PropertyMap) (identifier *string, outputs map[string]any, err error)
Create(ctx context.Context, urn resource.URN, inputs resource.PropertyMap, timeout time.Duration) (identifier *string, outputs resource.PropertyMap, err error)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a breaking change but we are expecting this interface to be internal? .. We're on v1.5.0. Nothing consumes it in other codebases? Should we work harder here as in introducing a side-by-side interface?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this interface is internal. There's no way somebody could use this interface and plug it into aws-native unless they fork aws-native. It's used internally to wrap arbitrary custom resources:

p.customResources = map[string]resources.CustomResource{
metadata.ExtensionResourceToken: resources.NewExtensionResource(p.ccc),
}

@flostadler
Copy link
Contributor Author

The test coverage of the touched files is mostly through integration tests. I'll try to add some more tests to cover parts of this with units as well

I added unit tests for the provider's CRUD operations. Coverage wise we should be good now and I managed to uncover a bug: #1796

@flostadler flostadler requested a review from t0yv0 November 4, 2024 18:01
@flostadler flostadler merged commit 2962615 into master Nov 5, 2024
18 checks passed
@flostadler flostadler deleted the flostadler/refactor-custom-resources branch November 5, 2024 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants