-
Notifications
You must be signed in to change notification settings - Fork 6
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
Add CustomPlugin and WorkerConfiguration resources along with tagging support for all resources #14
Add CustomPlugin and WorkerConfiguration resources along with tagging support for all resources #14
Conversation
fff467f
to
98189da
Compare
… support for all resources
98189da
to
44b3ed9
Compare
@@ -36,7 +36,7 @@ public BaseHandlerException translateToCfnException( | |||
} | |||
|
|||
if (exception instanceof BadRequestException) { | |||
return new CfnInvalidRequestException(ResourceModel.TYPE_NAME, exception); | |||
return new CfnInvalidRequestException(exception.getMessage(), exception); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why only this exception changed from resource type to exception message? I see there are other exceptions that being handled differently
*/ | ||
public static Map<String, String> generateTagsToAdd(final Map<String, String> previousTags, final Map<String, String> desiredTags) { | ||
return desiredTags.entrySet().stream() | ||
.filter(e -> !previousTags.containsKey(e.getKey()) || !Objects.equals(previousTags.get(e.getKey()), e.getValue())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: the e reads like a exception by a glance, consider use a proper name such as desiredTag
} | ||
|
||
/** | ||
* Request to add tags to a resource |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
request to remove tags from a resource
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't check all the comments in details, please review the accuracy and correctness of the comments, especially the content in docs
@@ -79,6 +83,8 @@ protected ProgressEvent<ResourceModel, CallbackContext> handleRequest( | |||
return ProgressEvent.progress(request.getDesiredResourceState(), callbackContext) | |||
.then(progress -> | |||
verifyUpdatable(proxy, proxyClient, progress, "AWS-KafkaConnect-Connector::PreUpdateCheck")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does verifyUpdatable also check if tags got changed or not? if customer only changed tags, it should be treated as updatable and move to the next step.
if (!removedTags.isEmpty()) { | ||
|
||
final UntagResourceRequest untagResourceRequest = Translator.untagResourceRequest(desiredModel, removedTags); | ||
try { | ||
proxyClient.injectCredentialsAndInvokeV2(untagResourceRequest, proxyClient.client()::untagResource); | ||
logger.log(String.format("Removed %d tags", removedTags.size())); | ||
} catch (final AwsServiceException e) { | ||
throw exceptionTranslator.translateToCfnException(e, identifier); | ||
} | ||
} | ||
|
||
// calculate tags to update based on Tags (key + value) | ||
if (!addedTags.isEmpty()) { | ||
final TagResourceRequest tagResourceRequest = Translator.tagResourceRequest(desiredModel, addedTags); | ||
try { | ||
proxyClient.injectCredentialsAndInvokeV2(tagResourceRequest, proxyClient.client()::tagResource); | ||
logger.log(String.format("Added %d tags", addedTags.size())); | ||
} catch (final AwsServiceException e) { | ||
throw exceptionTranslator.translateToCfnException(e, identifier); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this logic here idempotent and handle partial failures well?
Let's say when tags being removed successfully but then the add tags failed, what happens?
|
||
return describeConnectorResponse; | ||
|
||
private ProgressEvent<ResourceModel, CallbackContext> verifyNonCreateOnlyFieldsHaveToBeUpdated( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: verifyUpdatableFieldsGotChanged? the current name is a bit confusing.
throw exceptionTranslator.translateToCfnException(e, identifier); | ||
} | ||
|
||
logger.log(String.format("%s [%s] created successfully.", ResourceModel.TYPE_NAME, identifier)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder how informative is this by using just name as logging identifier, better to include customer account ID as well. Although it's not part of request body, it should be accessible from request context or similar parts.
case DELETING: | ||
throw new CfnResourceConflictException( | ||
ResourceModel.TYPE_NAME, | ||
model.getCustomPluginArn(), | ||
String.format("Another process is deleting this %s", ResourceModel.TYPE_NAME)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When got to the stage where checking if resource is stablised or not, it means the create request got a successful response. Given the locking mechanism we have, deleting shouldn't be a possible case to handle, why do we think this case is necessary to be handled?
successMessagePattern, | ||
ResourceModel.TYPE_NAME, | ||
describeCustomPluginRequest.customPluginArn(), | ||
customPluginState == null ? "unknown" : customPluginState.toString())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the reason to handle the customPluginState to be null case? It seems implying describeCustomPlugin call doesn't handle exception properly and setting state to null, if that's not the case, we can remove this check. Another way to look at this, if pluginArn can't be null then pluginState is the same
if (describeCustomPluginRequest.customPluginArn() == null) { | ||
throw new CfnNotFoundException(ResourceModel.TYPE_NAME, null); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In which case custom plugin Arn will be null? It looks like to me it's a parameter that customers provid and then we use it to describe the resource. If so, here's is more appropriate to throw a 400 instead of 404.
} catch (final AwsServiceException e) { | ||
throw exceptionTranslator.translateToCfnException(e, identifier); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although we are validating the resource state by describing the resource, it's still a best effort which covers most cases. The edge case here is that the the resource can be deleted/updated after passes the validation phase, therefore, additional logics are needed.
- If resource is being deleted, it can choose make the operation idempotent and move on. Another option is to fail the request. Better to check how other services are handling this case
- If resource is being updated, we need to fail the operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One way to tackle this is to move the validation resource after the delete call has been dispatched.
|
||
return ProgressEvent.<ResourceModel, CallbackContext>builder() | ||
.resourceModels(models) | ||
.nextToken(nextToken) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this progressEvent handles nextToken automatically, and make additional call if token exist and stops when token is null?
return Collections.emptyMap(); | ||
} | ||
return tags.stream() | ||
.filter(tag -> tag.getValue() != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we not support key only tags? Please test this in API
desiredModel, | ||
callbackContext) | ||
.translateToServiceRequest(translator::translateToReadRequest) | ||
.makeServiceCall(this::validateResourceExists) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the delete comment, the validateResource logic is likely need to be expanded and move to after the updateAPI call dispatched and handles the resource to be sure we are verifying against the real status of the resource and avoid any race conditions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not going to repeat similar comments, but some previous comment on code pattern applies to other resources as well, please verify them even though they don't have a comment
Issue #, if available:
Description of changes:
AWS::KafkaConnect::CustomPlugin
andAWS::KafkaConnect::WorkerConfiguration
CFN resources.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.