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

Added the default ignore config for service disable error #476

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

ParthaI
Copy link
Contributor

@ParthaI ParthaI commented Aug 7, 2023

Integration test logs

Logs
Add passing integration test logs here

Example query results

Results
Add example SQL query results here (please include the input queries as well)

@ParthaI ParthaI self-assigned this Aug 7, 2023
@ParthaI ParthaI marked this pull request as draft August 7, 2023 06:53
@ParthaI ParthaI marked this pull request as ready for review August 10, 2023 11:17
@cbruno10
Copy link
Contributor

@johnsmyth I think this feature is helpful for ignoring errors better, especially when the error codes we get back are simple and lack details, e.g., 403, 500.

One thought I had was, would more flexibility in be helpful or too complex?

For instance:

ignore_error_configs = [
  { codes: ["400", "403"], messages: ["foo", "bar"] }, // Ignore errors with at least one of these codes and one of these messages
  { codes: ["500"], // Ignore errors with this code
  { messages: ["^.*foobar$"] // Ignore errors whose message matches this pattern
]

The main use case would be ignoring specific code/message combinations, e.g., if multiple error codes had similar messages, but typing it out, it seems a little more complex than required in this case and in most plugins.

@johnsmyth
Copy link
Contributor

@cbruno10 You are correct that The main use case would be ignoring specific code/message combinations, e.g., if multiple error codes had similar messages. Not knowing what these error messages look like, or how common that case is, Its hard to make a recommendation. If it is uncommon / unlikely, I would probably opt for the simpler, backward-compatible solution.

Copy link
Contributor

@cbruno10 cbruno10 left a comment

Choose a reason for hiding this comment

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

@ParthaI Please see review comments, thanks!

config/gcp.spc Outdated
@@ -20,6 +20,9 @@ connection "gcp" {
# If not set, no impersonation is done.
#impersonate_service_account = "YOUR_SERVICE_ACCOUNT"

# `ignore_error_messages` (optional) - List of additional GCP error message pattern to ignore for all queries.
# ignore_error_messages = ["API has not been used", "other regex"]
Copy link
Contributor

Choose a reason for hiding this comment

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

@ParthaI Is there a more exact regex (using ^, $) we should add as an example here, in particular for the "API has not been used" case? We can probably remove other regex as it's not helpful.

Choose a reason for hiding this comment

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

This is a really good addition to handle cases where, google uses the same 403 error code when - API are not enabled and when Quota exceeded. An exact regex mapping example to an error message would sure be helpful.

Copy link
Contributor

Choose a reason for hiding this comment

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

For reference, this is reported as this:

ERROR: googleapi: Error 403: Cloud DNS API has not been used in project XXX before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/dns.go…
Details:
[
  {
    "@type": "type.googleapis.com/google.rpc.Help",
    "links": [
      {
        "description": "Google developers console API activation",
        "url": "https://console.developers.google.com/apis/api/dns.googleapis.com/overview?project=XXX"
      }
    ]
  },
  {
    "@type": "type.googleapis.com/google.rpc.ErrorInfo",
    "domain": "googleapis.com",
    "metadata": {
      "consumer": "projects/XXX",
      "service": "dns.googleapis.com"
    },
    "reason": "SERVICE_DISABLED"
  }
]
, accessNotConfigured (SQLSTATE HV000)

So I think the current example with API has not been used would be enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cbruno10, I have added the example for the exact regex (using ^, $) i.e ignore_error_messages = ["^.*API\\s*has\\s*not\\s*been\\s*used.*$"]. Also we can pass a message just like a string format, in both of the case the code changes are working fine.

NOTE: In the .spc file, we should use \\ instead of \ for the regex pattern to avoid errors related to escape characters. Otherwise, parsing the .spc file might result in an error like "Invalid escape sequence: The symbol "d" is not a valid escape sequence selector."

if gerr, ok := err.(*googleapi.Error); ok {
for _, pattern := range gcpConfig.IgnoreErrorMessages {
re := regexp.MustCompile(pattern)
result := re.FindString(types.ToString(gerr.Message))
Copy link
Contributor

Choose a reason for hiding this comment

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

Does GCP ever send messages that don't have the Message property? If so, does this code still handle everything ok?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I haven't encountered any errors without a message property. Additionally, we are converting errors of type googleapi.Error, which always includes a message property. I've tested it multiple times with various connection combinations, and it's working correctly, handling errors as expected.

If an error does not contain a message property, the code block above will not function as it is designed to handle errors based on their error message. In cases where the message property is not available, an alternative approach is to configure the ignore_error_codes in the .spc file. This will allow the following line of code to handle the error.

According to the GCP API design documentation, errors include a message property. However, it's important to note that Error messages are not part of the API surface. They are subject to changes without notice. Application code should not rely heavily on error messages as they may change.

if gerr, ok := err.(*googleapi.Error); ok {
for _, pattern := range gcpConfig.IgnoreErrorMessages {
re := regexp.MustCompile(pattern)
result := re.FindString(types.ToString(gerr.Message))
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this function support matching on full regular expressions? How is this different than the regex Match function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, this function support matching on full regular expressions.

  • *func (re Regexp) FindString(s string) string
    FindString returns a string holding the text of the leftmost match in s of the regular expression. If there is no match, the return value is an empty string, but it will also be empty if the regular expression successfully matches an empty string. Use FindStringIndex or FindStringSubmatch if it is necessary to distinguish these cases.

  • *func (re Regexp) Match(b []byte) bool
    Match reports whether the byte slice b contains any match of the regular expression re.

IMO, it would be better to use MatchString function here. I can see in most of the place we use MatchString function to validate patterns. https://github.com/search?q=repo%3Aturbot%2Fsteampipe%20MatchString&type=code

I have replace the function FindString to MatchString.

}
}

if !hasIgnoredErrorCodes(d.Connection) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need this block still?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed this block of code as we do not need those.

Copy link
Contributor

@cbruno10 cbruno10 left a comment

Choose a reason for hiding this comment

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

@ParthaI Please see comments, thanks!

@@ -20,6 +20,9 @@ connection "gcp" {
# If not set, no impersonation is done.
#impersonate_service_account = "YOUR_SERVICE_ACCOUNT"

# `ignore_error_messages` (optional) - List of additional GCP error message pattern to ignore for all queries.
# ignore_error_messages = ["^.*API has not been used.*$"]
Copy link
Contributor

Choose a reason for hiding this comment

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

What error does a user receive if an invalid regex is passed in?

Also, do users need to use ^ and $, or will we still match without those explicitly included in a pattern?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The user will receive an error error parsing regexp: invalid escape sequence: during the query execution if a user provide an invalid regex.

User may include ^ and $ or may not be, in both of the case the code changes are working fine.

@@ -20,6 +20,9 @@ connection "gcp" {
# If not set, no impersonation is done.
#impersonate_service_account = "YOUR_SERVICE_ACCOUNT"

# `ignore_error_messages` (optional) - List of additional GCP error message pattern to ignore for all queries.
Copy link
Contributor

Choose a reason for hiding this comment

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

Is an error ignored if the message matches a value from here OR if the error code matches the other config arg?

Copy link
Contributor Author

@ParthaI ParthaI Oct 4, 2023

Choose a reason for hiding this comment

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

If the ignore_error_messages has been set and the pattern matches with the error message the error will be ignore from here.

// Add to support regex match as per error message
for _, pattern := range gcpConfig.IgnoreErrorMessages {
re := regexp.MustCompile(pattern)
result := re.MatchString(types.ToString(gerr.Message))
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to cast with types.toString? What type is the Message property?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, is there ever a case where Message is not included as part of an error?

Copy link
Contributor Author

@ParthaI ParthaI Oct 4, 2023

Choose a reason for hiding this comment

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

Do we need to cast with types.toString? What type is the Message property?

No, we do not need to cast with types.toString, the Message property it self a string.

Also, is there ever a case where Message is not included as part of an error?

No, I have not face such type of scenario as of now.

Copy link

github-actions bot commented Dec 3, 2023

This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the stale No recent activity has been detected on this issue/PR and it will be closed label Dec 3, 2023
@ParthaI ParthaI removed the stale No recent activity has been detected on this issue/PR and it will be closed label Dec 4, 2023
Copy link

github-actions bot commented Feb 2, 2024

This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the stale No recent activity has been detected on this issue/PR and it will be closed label Feb 2, 2024
Copy link

github-actions bot commented Mar 4, 2024

This PR was closed because it has been stalled for 90 days with no activity.

@github-actions github-actions bot closed this Mar 4, 2024
@cbruno10 cbruno10 reopened this Oct 15, 2024
@github-actions github-actions bot removed the stale No recent activity has been detected on this issue/PR and it will be closed label Oct 15, 2024
@pdecat
Copy link
Contributor

pdecat commented Oct 16, 2024

FWIW, I've squashed and rebased the commits from this PR here: https://github.com/pdecat/steampipe-plugin-gcp/tree/issue-286, and can confirm it works great :)

I've integrated the changes in our custom build of the plugin here: https://github.com/pdecat/steampipe-plugin-gcp/tree/dev

@pdecat
Copy link
Contributor

pdecat commented Nov 12, 2024

This PR is also working great to ignore issues when new regions are added, like is currently happening with northamerica-south1 (Queretaro):

2024-11-12 10:38:10.814 UTC [ERROR] steampipe-plugin-gcp.plugin: [ERROR] 1731407888653: gcp_cloud_run_service.listCloudRunServices:
  api_error=
  | googleapi: Error 400: region: Unsupported region northamerica-south1
  | Details:
  | [
  |   {
  |     "@type": "type.googleapis.com/google.rpc.BadRequest",
  |     "fieldViolations": [
  |       {
  |         "description": "Unsupported region northamerica-south1",
  |         "field": "region"
  |       }
  |     ]
  |   }
  | ]
  | , badRequest

The following configuration allows to ignore them (along with service disabled errors):

connection "gcp" {
  plugin = plugin.gcp

  ignore_error_messages = [
    "^.*API has not been used.*$",
    "^.*Unsupported region.*$",
  ]
}

Comment on lines 28 to 39

if gerr, ok := err.(*googleapi.Error); ok {

// Add to support regex match as per error message
for _, pattern := range gcpConfig.IgnoreErrorMessages {
re := regexp.MustCompile(pattern)
result := re.MatchString(gerr.Message)
if result {
return true
}
}

Copy link
Contributor

@pdecat pdecat Nov 28, 2024

Choose a reason for hiding this comment

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

Turns out not all Google Cloud SDK APIs use the googleapi.Error type, e.g. Redis APIs, so I've altered this part of the code to compare the error message of all errors:

Suggested change
if gerr, ok := err.(*googleapi.Error); ok {
// Add to support regex match as per error message
for _, pattern := range gcpConfig.IgnoreErrorMessages {
re := regexp.MustCompile(pattern)
result := re.MatchString(gerr.Message)
if result {
return true
}
}
logger := plugin.Logger(ctx)
logger.Trace("ignore_error_predicate.shouldIgnoreErrorPluginDefault", "err.Error()", err.Error())
// Add to support regex match as per error message
for _, pattern := range gcpConfig.IgnoreErrorMessages {
logger.Trace("ignore_error_predicate.shouldIgnoreErrorPluginDefault", "message_pattern", pattern)
// TODO: maybe compile these at the connection level for performance reasons
re := regexp.MustCompile(pattern)
result := re.MatchString(err.Error())
if result {
logger.Debug("ignore_error_predicate.shouldIgnoreErrorPluginDefault", "ignore_error_message", err.Error())
return true
}
}

Without this change, API has not been used cannot be ignored for Redis API calls.

Note that this requires enabling multiline regex matching with (?s) as errors are serialized as:

2024-11-28 08:23:11.222 UTC [TRACE] steampipe-plugin-gcp.plugin: [TRACE] 1732782190328: ignore_error_predicate.shouldIgnoreErrorPluginDefault:
  err.Error()=
  | rpc error: code = PermissionDenied desc = Google Cloud Memorystore for Redis API has not been used in project my-project before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/redis.googleapis.com/overview?project=my-project then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
  | error details: name = ErrorInfo reason = SERVICE_DISABLED domain = googleapis.com metadata = map[consumer:projects/my-project service:redis.googleapis.com]
  | error details: name = Help desc = Google developers console API activation url = https://console.developers.google.com/apis/api/redis.googleapis.com/overview?project=my-project

E.g.:

                ignore_error_messages = [
                    "(?s)^.*API has not been used.*$",
                    "(?s)^.*Unsupported region.*$",
                ]

Also added some logs to the error code checks right below.

Pushed the changes here: pdecat@d8b31a2

Can submit an PR targeting this PR's branch if you want.

Copy link
Contributor

Choose a reason for hiding this comment

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

@pdecat Yes please, we'd greatly appreciate a PR!

Copy link
Contributor

Choose a reason for hiding this comment

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

Submitted #688

* fix: ignore error messages from all error types
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.

6 participants