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

Add configuration validation in clients #59

Merged
merged 29 commits into from
Jun 24, 2020
Merged

Conversation

sarah-witt
Copy link
Collaborator

@sarah-witt sarah-witt commented Apr 23, 2020

What does this PR do?

  • Leaves most validation up to the client (besides form validation in the jenkins UI)
  • Does not attempt validation when the last instance is the same as the attempted parameters
  • Does not continuously log the same error when trying to create the same instance as before

What inspired you to submit this pull request?
#55

Description of the Change

  • Removes some duplicate validation in GlobalConfiguration to the DatadogClients
  • Modifies getInstance so that it does not log the same message over and over again
  • Changes getPort and setPort to use Integers since port is an Integer

Alternate Designs

  • Only remove the log statements and do not refactor the code (we want the log statements at some point)

Possible Drawbacks

  • less validation, so may miss some errors that global config caught before

Verification Process

  • unit tests
  • run the instance locally and check logs to see that they are not overpopulated
  • TODO: more validation and cleanup, and addressing build failure

Additional Notes

Release Notes

Review checklist (to be filled by reviewers)

  • Feature or bug fix MUST have appropriate tests (unit, integration, etc...)
  • PR title must be written as a CHANGELOG entry (see why)
  • Files changes must correspond to the primary purpose of the PR as described in the title (small unrelated changes should have their own PR)
  • PR must have one changelog/ label attached. If applicable it should have the backward-incompatible label attached.
  • PR should not have do-not-merge/ label attached.
  • If Applicable, issue must have kind/ and severity/ labels attached at least.

Copy link
Contributor

@FlorianVeaux FlorianVeaux left a comment

Choose a reason for hiding this comment

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

I know it's still a draft, but I wanted to add a few comments already.

instance.setLogIntakeConnectionBroken(true);
logger.severe("Connection broken, please double check both your Log Intake URL and Key");
}
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

So validation will pass even though both the url and the logIntakeUrl are invalid (or the apiKey is invalid).
Maybe we should at least fail it metrics can't be submitted?

Also to come back to the UI part, we should be able to display a FormWarning if the plugin can't connect.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh that's a good idea. I agree there are more validations that can be performed.

@@ -588,4 +612,9 @@ private String getJenkinsVersion(){
return this.jenkinsVersion;
}

private static boolean isCollectBuildLogEnabled(){
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't like that we need to access the config from here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is also currently in DogstatsdClient. I'm not sure the best way to check for logs being enabled.

@sarah-witt sarah-witt changed the title Add configuration validation Add configuration validation in clients Apr 28, 2020
@sarah-witt sarah-witt marked this pull request as ready for review April 29, 2020 14:59

return status;
}catch(Exception e){
// Intercept all FormException instances.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure what the effect of this is. Are we sure the change is safe ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hm I'm not completely sure, I know FormExceptions are the most common, and they should be thrown, but maybe unexpected errors should be caught and logged.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I added it back- I agree that having this safeguard is more important than the cleanliness of the code.

Copy link
Contributor

Choose a reason for hiding this comment

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

In theory java should let you know about all exceptions and force you to catch or rethrow them except if they are unchecked exception like RuntimeExceptions.
So I think you should be able to ensure that all exceptions are caught?


DatadogUtilities.severe(logger, e, null);
if(client != null) {
// There are no reasons at this point client should be null.
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's update the comment here, client is expected to be null if connection is impossible.

Copy link
Contributor

Choose a reason for hiding this comment

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

And let's reverse the condition:

if(client == null) {
    return null
}
client.setDefaultIntakeConnectionBroken(false);
client.setLogIntakeConnectionBroken(false);
// Persist global configuration information
save();
return status;

Copy link
Contributor

Choose a reason for hiding this comment

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

I also think that instead of returning status here we should return true. And at the top of the method do this:

if(!super.configure(req, formData)){
    return false
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sure!

@@ -54,7 +54,9 @@ of this software and associated documentation files (the "Software"), to deal
*/
public class DatadogHttpClient implements DatadogClient {

private static DatadogClient instance;
private static DatadogClient instance = null;
private static boolean failedLastValidation = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's have a comment to tell why it's useful.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sure!

DatadogHttpClient newInstance = new DatadogHttpClient(url, logIntakeUrl, apiKey);
DatadogHttpClient httpInstance = (DatadogHttpClient) instance;
if (httpInstance != null && httpInstance.equals(newInstance)) {
if (DatadogHttpClient.failedLastValidation) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We will need a way to retry validation every X minutes. What if failedLastValidation is true because of a network failure ? You'd require a restart of Jenkins to fix

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hmm that's true. I will look into a way to do this.

Copy link
Contributor

Choose a reason for hiding this comment

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

We still need this to be addressed

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I know, I haven't thought of a great approach yet. Do you have any ideas?

Copy link
Collaborator Author

@sarah-witt sarah-witt Jun 17, 2020

Choose a reason for hiding this comment

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

So, thinking it through, in the case of a network failure, it wouldn't require a restart of jenkins, it would just require entering different credentials (and then entering the correct ones). It isn't the best solution, but I'm not sure how likely this scenario is.

DatadogHttpClient.lastInstance = new DatadogHttpClient(url, logIntakeUrl, apiKey);
if (enableValidations) {
try {
validateCongiguration(url, logIntakeUrl, apiKey);
Copy link
Contributor

Choose a reason for hiding this comment

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

Reopening: this should not be a static method.

DatadogHttpClient.instance = newInstance;
try {
validateCongiguration(url, logIntakeUrl, apiKey);
} catch(RuntimeException e){
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's not use unchecked exception for validation.

@@ -124,6 +122,68 @@ private DatadogHttpClient(String url, String logIntakeUrl, Secret apiKey) {
this.logIntakeUrl = logIntakeUrl;
}

public static void validateCongiguration(String url, String logIntakeUrl, Secret apiKey) throws RuntimeException {
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: validateConfiguration*

Copy link
Contributor

Choose a reason for hiding this comment

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

Should not be static

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's use checked exception instead

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated!

}

@Override
public int hashCode() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Auto generated ? Let's indicate it

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I based it off of the method from our other hashCode methods; it was recommended to override hashCode since I overrode equals

@@ -32,6 +32,7 @@ of this software and associated documentation files (the "Software"), to deal
import org.datadog.jenkins.plugins.datadog.DatadogUtilities;
import org.datadog.jenkins.plugins.datadog.util.SuppressFBWarnings;
import org.datadog.jenkins.plugins.datadog.util.TagsUtil;
import org.apache.commons.lang.StringUtils;

import java.io.*;
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comments as for DatadogHttpClient

if (enableValidations) {
DatadogHttpClient.instance = newInstance;
try {
newInstance.validateConfiguration(url, logIntakeUrl, apiKey);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
newInstance.validateConfiguration(url, logIntakeUrl, apiKey);
newInstance.validateConfiguration();

You don't need the args because it's not static anymore

ofek
ofek previously approved these changes May 13, 2020
Copy link
Collaborator

@ofek ofek left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@jetersen jetersen left a comment

Choose a reason for hiding this comment

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

I do not see how this PR fixes the issue of using the LogLevel.INFO

pom.xml Outdated
@@ -5,7 +5,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>3.56</version> <!-- or whatever the newest version available is -->
<version>4.1</version> <!-- or whatever the newest version available is -->
Copy link
Member

@jetersen jetersen May 19, 2020

Choose a reason for hiding this comment

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

This seems ill adviced:
https://github.com/jenkinsci/plugin-pom/blob/88cb710c1b7244bf5f885e16fc9f0baef1ef2661/pom.xml#L53
Please at least specify a Jenkins.version property

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hi, @jetersen!
This change was to just update the parent pom version. It was also included in this PR as well, which is ready to be merged: https://github.com/jenkinsci/datadog-plugin/pull/57/files#diff-600376dffeb79835ede4a0b285078036R8 Adding a minimum jenkins version is out of the scope for this PR, but it’s a good idea that we should do in a later PR.

@sarah-witt
Copy link
Collaborator Author

I do not see how this PR fixes the issue of using the LogLevel.INFO

Thanks for the review @jetersen! I agree this PR doesn’t solve the issue of the continuous DatadogCountersPublisher logs- this was only meant to resolve the null api key logs issue. Can we use #63 to address the DatadogCountersPublisher issue?

Comment on lines +656 to +657
return DatadogUtilities.getDatadogGlobalDescriptor() != null &&
DatadogUtilities.getDatadogGlobalDescriptor().isCollectBuildLogs();
Copy link
Member

@jetersen jetersen May 19, 2020

Choose a reason for hiding this comment

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

Your doing a lookup twice 😓 and your using an more expensive get in the method called.

You should use:

ExtensionList.lookupSingleton(DatadogGlobalConfiguration.class);

Also the method could be moved to the DatadogGlobalConfiguration class, basically moving it to where it belongs.
See here for example:
https://github.com/jenkinsci/azure-keyvault-plugin/blob/ef3a5eb4413f7ecd47d6532735604c52fceaaef0/src/main/java/org/jenkinsci/plugins/azurekeyvaultplugin/AzureKeyVaultGlobalConfiguration.java#L241-L243

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That sounds like a good idea, so we should refactor getDatadogGlobalDescriptor() and move it to DatadogGlobalConfiguration?

Copy link
Contributor

Choose a reason for hiding this comment

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

There is definitely an opportunity to clean this up, but let's cover it in a separate PR.

Copy link
Member

Choose a reason for hiding this comment

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

@sarah-witt I see you never picked up this suggestion 😅

Copy link
Contributor

Choose a reason for hiding this comment

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

Some changes were implemented here

Copy link
Member

Choose a reason for hiding this comment

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

Ah you kept DatadogUtilities.getDatadogGlobalDescriptor 😅 Logically I would prefer DatadogGlobalConfiguration.get()

Copy link
Contributor

@mgarabed mgarabed left a comment

Choose a reason for hiding this comment

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

🔥 LGTM - tested this out locally and only see a single log line when the API key is invalid.

@sarah-witt sarah-witt merged commit 76cbe15 into master Jun 24, 2020
@sarah-witt sarah-witt deleted the sarah/validate-config branch June 24, 2020 14:31
sarah-witt added a commit that referenced this pull request Jun 24, 2020
* Add configuration validation

* Create .equals method and use synchronization

* Remove try catch in configure and enforce use of POST

* Simplify logic in configure

* Don't create instance if config is invalid

* Remove IOException

* Throw form exception

* Remove exception and post

* Fiz style

* Check for zero as port

* Use parseInt instead of Number Utils

* Remove zero check

* Update pom

* Fix style of imports

* Add back extra safeguards for exceptions in configuration

* Update exception type and use assertThrows in tests

* Validation does not need parameters

* Reset config for testing

* Remove reset

* Remove unneeded resetConfig

* Remove unneeded validation

* Move hostname validation

* Style

* Refactor validate url

* Simplify equals methods

* Update equals and remove imports

* Update instance type
@FlorianVeaux FlorianVeaux added the changelog/Fixed Fixed features results into a bug fix version bump label Jul 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog/Fixed Fixed features results into a bug fix version bump
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants