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 support for fetching rules with API client #508

Merged

Conversation

bobmshannon
Copy link
Contributor

This PR adds support for fetching rules via the /api/v1/rules endpoint using the API client. Currently, the API client exposes no way to do this and it would be nice to have for external systems that wish to retrieve this information.

cc @beorn7

Signed-off-by: Bob Shannon <bshannon@palantir.com>
type RuleGroup struct {
Name string `json:"name"`
File string `json:"file"`
Rules []Rule `json:"rules"`
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since a Rule can be either recording or alerting, I'm not sure if we actually want to use a stronger type here with two fields RecordingRules and AlertingRules, or put everything in the same list to preserve the rule order like https://github.com/prometheus/prometheus/blob/master/web/api/v1/api.go#L721 does.

@beorn7
Copy link
Member

beorn7 commented Nov 21, 2018

That one is for @krasi-georgiev . 😄

Copy link
Contributor

@krasi-georgiev krasi-georgiev left a comment

Choose a reason for hiding this comment

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

LGTM , but would be best if @simonpasquier and @mxinden can also have a quick look.

One thing I don't like is that we are using server mocks for the tests, but that is a story for another PR tracking in #485 (comment)

Copy link
Member

@mxinden mxinden left a comment

Choose a reason for hiding this comment

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

Thanks for looking into this @bobmshannon. I am hoping that in the future we could generate clients based on e.g. OpenAPI specifications like we will soon do in github.com/prometheus/alertmanager.

I have a couple of comments. What are your thoughts?

RuleTypeAlerting RuleType = "alerting"

// Possible values for RuleHealth.
RuleHealthGood = "ok"
Copy link
Member

Choose a reason for hiding this comment

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

@@ -67,6 +82,15 @@ const (
HealthGood HealthStatus = "up"
HealthUnknown HealthStatus = "unknown"
HealthBad HealthStatus = "down"

// Possible values for RuleType.
RuleTypeRecording RuleType = "recording"
Copy link
Member

Choose a reason for hiding this comment

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

Mhh, its a bummer that I didn't expose these as constants when I added this. Sorry about that. Feel free to propose a patch on prometheus/prometheus.

Groups []RuleGroup `json:"groups"`
}

type RuleGroup struct {
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

in general I am ok with duplicating types if this avoid a package dependency.
I follow the principle - import a package for its functionality and not for its types.

Here doesn't matter that much so I am ok either way.

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 primary reasons for not not importing RuleGroup from the v1 API package referenced above:

  • RuleGroup models the list of rules as interface{} - this requires the client to use type assertion to determine whether a given rule is a recording or alerting rule.
  • It adds an external dependency that the client will need to import in order to use this API client package.

Interval float64 `json:"interval"`
}

type Rule struct {
Copy link
Member

Choose a reason for hiding this comment

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

The name Rule is misleading, as recording rules do not expose e.g. Alerts.

Copy link
Member

Choose a reason for hiding this comment

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

Again, could we import structs from prometheus/prometheus instead?

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 think we should just create two new types here: RecordingRule and AlertingRule. Is there any reason why order needs to be preserved by putting both types of rules in the same array?

If we create these two new types, I think we'll need some changes to the imported structs, for example recordingRule and alertingRule are not exported so can't be consumed by this package:
https://github.com/prometheus/prometheus/blob/master/web/api/v1/api.go#L730
https://github.com/prometheus/prometheus/blob/master/web/api/v1/api.go#L743

@bobmshannon
Copy link
Contributor Author

I'm happy make the changes to this PR such that the types are imported from prometheus/prometheus, however I'll also need to make a patch to export some types so that they can be consumed here. Additionally, I think I'd prefer to keep the types encapsulated as much as possible so that clients don't need to import a whole bunch of external packages just to use the API client. Let me know what you all think.

As for using OpenAPI to generate the client code, agreed it would be a very nice place to get to.

@bobmshannon
Copy link
Contributor Author

@mxinden Do you mind having another look at this one? I addressed some of the comments and added new fields AlertRules and RecordingRules to the RuleGroup struct to provide stronger typing and reduce ambiguity from a client perspective.

I think that importing the types at this point may be more trouble than it's worth, and we should probably just plan to supercede this client with the OpenAPI generated one, however I could be wrong about this.

Signed-off-by: Bob Shannon <bshannon@palantir.com>
var recordingRules []RecordingRule

for _, rule := range v.Rules {
// Because both recording and alerting rules are stored in the same
Copy link
Member

Choose a reason for hiding this comment

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

They are stored in the same JSON array as the ordering among them matters (See prometheus/prometheus#4318 (comment) for more details). That way users can understand which rules depend on which.

I am not sure this is a blocker. But probably worth mentioning in a comment somewhere. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for pointing me to that.

To keep things consistent, I've modified the client to preserve rule order as returned by the API, and added some documentation on this behavior regarding how to use a type switch to access each recording or alerting rule.

@mxinden
Copy link
Member

mxinden commented Dec 10, 2018

On the one hand given the fact that this client is already tightly coupled with the prometheus/prometheus structs (e.g. when we change something in prometheus/prometheus this will likely break this client), I think this dependency should also be expressed in the code, hence importing it.

On the other hand according to the README of this repository we don't give any stability guarantees in regards to the client. Thereby I am fine with going either way.

Signed-off-by: Bob Shannon <bshannon@palantir.com>
// default:
// fmt.Printf("unknown rule type %s", v)
// }
type Rules []interface{}
Copy link
Member

Choose a reason for hiding this comment

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

Where is this type used? Am I missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice catch, fixed.

if !ok {
return errors.New("rule has no type field")
}
ruleJSON, err := json.Marshal(rule)
Copy link
Member

Choose a reason for hiding this comment

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

I am a bit confused here. You are marshaling a rule to unmarshal it?

How about unmarshaling the rule into something like this first:

struct {
  type string
}

and depending on type unmarshal as a recording or an alerting rule?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With that approach I think we'd still need to get the complete byte or JSON encoding of each individual rule (by using MarshalJSON) in order to unmarshal them into a typed recording or alerting rule. That said, I think most of the complexity here is from decoding the mixed type slice and there may not be a super elegant way to do it in Go.

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've made an update to this PR that should be easier to read and is more in-line with the approach suggested in this comment.

Bob Shannon added 2 commits December 11, 2018 08:31
Signed-off-by: Bob Shannon <bshannon@palantir.com>
Signed-off-by: Bob Shannon <bshannon@palantir.com>
Signed-off-by: Bob Shannon <bshannon@palantir.com>
@bobmshannon
Copy link
Contributor Author

@mxinden I've made some adjustments to this PR based on the most recent comments, please let me know what you think.

@bobmshannon
Copy link
Contributor Author

@beorn7 @mxinden Just wanted to circle back on this one, is there anything I can do to help push this one through? It would be really nice to have this functionality in the API client for my use-case and for any external system that fetches alert and rules data from Prometheus. Thanks in advanced. :)

@beorn7
Copy link
Member

beorn7 commented Jan 7, 2019

I'd like to see @mxinden and @krasi-georgiev to have the final look here.

@krasi-georgiev
Copy link
Contributor

yeah waiting for Max for the final input.

Copy link
Member

@mxinden mxinden left a comment

Choose a reason for hiding this comment

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

Given that the general preference seems to go towards duplication over dependency, this looks good to me.

I am sorry for the delayed response, just came back from a couple of weeks of vacation.

@bobmshannon
Copy link
Contributor Author

Great, thanks!

@krasi-georgiev krasi-georgiev merged commit 18d13ea into prometheus:master Jan 15, 2019
@krasi-georgiev
Copy link
Contributor

Thanks

@bobmshannon bobmshannon deleted the bs/rules_endpoint_support branch January 16, 2019 17:51
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.

None yet

4 participants