-
Notifications
You must be signed in to change notification settings - Fork 898
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
Create a hawkular client for partial endpoints #13814
Conversation
@miq-bot add_label providers/containers, bug |
@lucasponce @cben @simon3z could you please review? |
@josejulio @cfcosta Please could you also review this PR ? |
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.
Just some clarifications and some small questions.
port, | ||
authentication_token('default'), | ||
options[:alerts]) | ||
@clients ||= {} |
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.
Where is the @client
being defined then? Is it utilized anywhere else in the class?
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 think they use the returned variable and only use @client
and the new @clients
to save the connection for future calls.
Is that right @moolitayer ?
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.
Right, this is a memoization technique @client is defined only here. On the first call it will create and return the relevant client and from that point on it will return the stored value.
authentication_token('default'), | ||
options[:alerts]) | ||
@clients ||= {} | ||
@clients[options[:alerts] ? :alerts : :metrics] ||= self.class.raw_connect( |
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 don't like this options[:alerts] ? :alerts : :metrics
inside the hash accessor, can you extract it into a variable? Would make a lot more sense.
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.
Honestly I'm not a fan of creating variables that are not used.
(not a performance thing, only readability)
If you feel current code is not readable I suggest:
@clients ||= {}
@clients[
options[:alerts] ? :alerts : :metrics
] ||= self.class.raw_connect(
hostname,
port,
authentication_token('default'),
options[:alerts]
)
What do you think?
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 think the new alternative is more readable. I was also confused with the old one. WDYT @cfcosta ?
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.
changed this for now
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.
The variable would be used, just very locally:
client_type = options[:alerts] ? :alerts : :metrics
@clients[client_type] || = ...
But that highlights the fact there are approximately four representations of client type around here:
::Hawkular::Alerts::AlertsClient
vs::Hawkular::Metrics::Client
- :alerts vs :metrics here
- raw_connect takes positional boolean [3.5. connect takes named boolean]
Q: can any more endpoints become needed later? E.g. Openshift managerfetch_hawk_inv()
creates aggregated client then does.strings.get_data()
. - calling
alerts_client
(and maybemetrics_client
) instead ofconnect
.
Is it feasible to change raw_connect
and connect
interface to take symbol (:alerts vs :metrics) instead of booleans?
Then you have less representations, can do simpler options[:type] || :metrics
, and might not need {alerts,metrics}_client
aliases...
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.
There are only two options so It makes more sense to use a boolean instead of a string with two options (openshift cluster only exposes alerts and metrics, string is a type of metric)
Raw connect and connect have their reasons to exists - interfaces calling connect use a context
and raw_connect requires intimate knowledge of provider parameters. If you take a look at other providers they all look exactly the same. container_provider_mixin does something a little different: it passes the options forward, but I see no point in passing some of the parameters as options and some positionals.
@cfcosta Thanks for the review |
) | ||
end | ||
|
||
def alerts_client |
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.
Might also be worth to create a metrics_client
while you are at it.
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.
Sure why not
173903c
to
0fe66a5
Compare
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.
LGTM
@cben @josejulio Please review |
I still dislike the boolean because "alerts false" here doesn't mean "the opposite or alerts" or "don't fetch alerts", it means "the other unrelated thing out of two"... LGTM on the PR, it fixes a bug and the code is no worse than before. P.S. if the options hash grows any new parameters in the future, it's easy for the bug to re-appear. P.P.S. AFAIK a Hawkular::Client currently constructs new RestClient for every request, and a RestClient currently opens new http connection for every request. So the memoization is not really helping(?), just dropping it is also an option. |
@cben +1 to dropping memoization, on a stylistic level it makes the code weird to read, and as you said it does not exactly do anything. In case we're doing lots of that kind of memoization, we can start using Memoist, which is a nice, elegant way of doing memoization. And as of Ruby 2.1 (I guess) something like this is possible: memoize def foo; end And it would be equivalent to do: def foo; end
memoize :foo |
Outside the scope of this pr:
I have my thoughts about both of these, but they are both out of scope of this PR in the scope of this pr:
They both have good reasons, the difference as I see it is;
I prefer option a here |
@cben @cfcosta @josejulio please review |
I prefer option b, because its not default behaviour OR other behaviour, but two different kinds of behaviour being switched by a flag. Going even further, I prefer something like this: def self.client_for(type)
case type
when :metrics
::Hawkular::Metrics::Client
when :alerts
::Hawkular::Alerts::AlertsClient
else
raise ArgumentError, "Client not found for #{type}"
end
end
def self.raw_connect(..., type = :alerts)
client_for(type).new(...)
end |
@cben @josejulio are you happy with @cfcosta's suggestion? |
@cben @josejulio sorry for nagging but I have a ton of other stuff dependant on this |
@cfcosta suggestion is good |
That's right, but some clients (e.g. I guess the whole Hawkular client could benefit from checking it lazily (I suppose this PR wouldn't exist if it was like that). |
Thanks @josejulio |
Love @cfcosta's suggestion. |
0fe66a5
to
24d6f79
Compare
@cben @josejulio @cfcosta please review |
LGTM |
@@ -35,21 +35,42 @@ def self.verify_ssl_mode | |||
OpenSSL::SSL::VERIFY_NONE | |||
end | |||
|
|||
def self.client_for(type) |
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.
@moolitayer why don't you keep this in raw_connect
?
@miq-bot assign moolitayer |
24d6f79
to
5998dc6
Compare
@simon3z can we merge this? |
port, | ||
authentication_token('default'), | ||
options[:alerts]) | ||
raise ArgumentError, "Client not found for #{type}" unless CLIENT_KLASSES.keys.include?(options[:type]) |
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.
@moolitayer why do you need this? don't you get it for free from raw_connect
?
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 was worried about the assignment to @client[:something_unexpected] but I guess such assignment would never happen.
Removing
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.
Also not necessary to do the check twice.
@@ -11,6 +11,11 @@ class Hawkular::DatawarehouseManager < ManageIQ::Providers::DatawarehouseManager | |||
DEFAULT_PORT = 80 | |||
default_value_for :port, DEFAULT_PORT | |||
|
|||
CLIENT_KLASSES = { |
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.
This forces the constants to be autoloaded before the class itself is loaded, so I'd advise against it. The later we manage to move constant loading the better.
client = alerts ? ::Hawkular::Alerts::AlertsClient : ::Hawkular::Metrics::Client | ||
client.new( | ||
def self.raw_connect(hostname, port, token, type = :alerts) | ||
raise ArgumentError, "Client not found for #{type}" unless CLIENT_KLASSES.keys.include?(type) |
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.
unless CLIENT_CLASSES[type]
Also, no need to name something klass
unless it conflicts with a keyword.
port, | ||
authentication_token('default'), | ||
options[:alerts]) | ||
raise ArgumentError, "Client not found for #{type}" unless CLIENT_KLASSES.keys.include?(options[:type]) |
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.
Also not necessary to do the check twice.
) | ||
end | ||
|
||
def alerts_client |
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.
Since you are already doing that, why not do it with metaprogramming? That way you don't need to add another method in case another client is added.
CLIENT_CLASSES.keys.each do |type|
define_method("#{type}_client") do
connect(:type => type)
end
end
5998dc6
to
1642239
Compare
1642239
to
aeb4035
Compare
Checked commit moolitayer@aeb4035 with ruby 2.2.6, rubocop 0.47.1, and haml-lint 0.20.0 |
@simon3z please review |
LGTM 👍 @miq-bot assign blomquisg |
Creating the aggregated client does a health check against all endpoints.
The Hawkular deployed in OpenShift does not include some of those endpoints (e.g inventory)
Extracted from #12773