Skip to content

[AMBARI-23130] Retrieve cluster template as artifact with passwords filtered out.#931

Merged
benyoka merged 19 commits into
apache:branch-feature-AMBARI-14714from
benyoka:AMBARI-23130-branch-feature-AMBARI-14714
Apr 11, 2018
Merged

[AMBARI-23130] Retrieve cluster template as artifact with passwords filtered out.#931
benyoka merged 19 commits into
apache:branch-feature-AMBARI-14714from
benyoka:AMBARI-23130-branch-feature-AMBARI-14714

Conversation

@benyoka
Copy link
Copy Markdown
Contributor

@benyoka benyoka commented Apr 6, 2018

What changes were proposed in this pull request?

Cluster templates are saved as artifacts during blueprint cluster creation and can be retrieved via the artifact resource provider API. Passwords are replaced with references during retrieval.

How was this patch tested?

Tested manually. Wrote new unit tests. Unit test results:
Tests run: 4834, Failures: 150, Errors: 301, Skipped: 73

@asfgit
Copy link
Copy Markdown

asfgit commented Apr 7, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ambari-Github-PullRequest-Builder/1705/
Test FAILed.
Test FAILured.

@benyoka benyoka changed the title [AMBARI-23130] branch feature ambari 14714 [AMBARI-23130] Retrieve cluster template as artifact with passwords filtered out. Apr 9, 2018
Copy link
Copy Markdown

@rnettleton rnettleton left a comment

Choose a reason for hiding this comment

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

This patch looks fine to me, just a few minor comments/questions below.

Can you please also ask @echekanskiy to review, since I think he implemented the original version of the SecretReference code?

Thanks.

Multimap<String, String> passwordProperties) {
return propertyMap.entrySet().stream().map(entry -> {
String propertyType = entry.getKey();
String newValue = passwordProperties.get(configType).contains(propertyType) ?
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor issue: If a configuration type is listed in a Blueprint/Cluster Creation template that is not a match with any known configuration type, will this throw a NullPointerException?

This might be a problem in cases where the cluster creation template has an error (mis-spelled config type name) or if a custom config type is specified that the stacks do not include.

Maybe we should catch this error here and log appropriately, if the code doesn't already filter out "unknown" config types at some other level.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Guava multimaps return an empty collection if the key is not in the map, that's one of their cool features.

public static final String CLUSTER_NAME_PROPERTY = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + CLUSTER_NAME;
public static final String SERVICE_NAME_PROPERTY = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + SERVICE_NAME;

public static final String PROVISION_REQUEST_ARTIFACT_NAME = "provision_cluster_request";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor concern:

I think this change is fine the way it is, but we might want to consider refactoring this in the future.

It may make more sense to keep any details about specific types of artifacts out of this class, and have a more generic strategy defined to allow for modifications of retrieved artifacts before the artifacts are returned to the caller.

Even having a static list of registered "filtering" or "updating" interfaces in this class might be better, and allow the resource provider code to only interact with that strategy interface.

As I mentioned, this current change is fine, but we might want to consider refactoring this if we find that other artifact types need to be persisted, and then retrieved in some custom fashion.

Configuration replacedConfiguration =
SecretReference.replacePasswordsInConfigurations(configuration, passwordProperties);
return Configurable.convertConfigToMap(replacedConfiguration);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you please extract this lambda expression to a function that can be referenced and tested more easily?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This method simply transforms a map with a lambda that is only 3 statements. I don't think further decomposition should be needed.

entry.getKey(),
applyToAllConfigurations(entry.getValue(), transform));
}
}).collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you please extract this lambda expression to a function that can be referenced and tested more easily?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I broke it up to smaller methods. I don't think it improves testing (the algorithm should be tested as a whole), on the other hand it hopefully improves readability.

catch (StackAccessException ex) {
throw new IllegalArgumentException(ex);
}
}).collect(toList());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you please extract this lambda expression to a function that can be referenced and tested more easily?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a very simple lambda (a simple method call within a try - catch - re-throw). I don't think it makes sense to decompose it further.

return getAllPasswordPropertiesInternal(metaInfo.getStacks());
}

private static SetMultimap<String, String> getAllPasswordPropertiesInternal(Collection<StackInfo> stacks) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Making this non-private would allow testing without the need for PowerMock.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Powermock is needed because of the static call to AmbariServer.getController(), not because this method is private.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I meant that this method could be tested instead of the one that calls AmbariServer.getController(). Most of the logic is in this one.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok.

Map<String, Map<String, String>> replacedConfigProps = configTypeEntry.getValue().entrySet().stream().collect(
toMap(Map.Entry::getKey, e -> replacePasswordsInPropertyMap(e.getValue(), configType, passwordProperties)));
return new SimpleEntry<>(configType, replacedConfigProps);
}).collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you please extract these lambda expressions to a function that can be referenced and tested more easily?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I am thinking on a simplification.

SECRET_PREFIX + ":" + configType + ":" + propertyType :
entry.getValue();
return new SimpleEntry<>(propertyType, newValue);
}).collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you please extract this lambda expression to a function that can be referenced and tested more easily?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is another a very simple map transformation written in java-8-lambda style rather as for-loop. I don't think further decomposition would add anything to readability or testability. I changed the indentation though to make it more readable.

@benyoka benyoka requested a review from echekanskiy April 9, 2018 15:51
@asfgit
Copy link
Copy Markdown

asfgit commented Apr 10, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ambari-Github-PullRequest-Builder/1730/
Test FAILed.
Test FAILured.

@asfgit
Copy link
Copy Markdown

asfgit commented Apr 10, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ambari-Github-PullRequest-Builder/1735/
Test FAILed.
Test FAILured.

@asfgit
Copy link
Copy Markdown

asfgit commented Apr 10, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ambari-Github-PullRequest-Builder/1736/
Test FAILed.
Test FAILured.

@benyoka benyoka merged commit 0e70cf2 into apache:branch-feature-AMBARI-14714 Apr 11, 2018
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.

4 participants