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

fixes #13618 - cache expensive vmware api calls #4238

Merged
merged 1 commit into from
Jan 31, 2017

Conversation

timogoebel
Copy link
Member

@timogoebel timogoebel commented Jan 27, 2017

In my dev environment the compute_resource_selected call got approx. 10 times faster. I'm really thrilled!

The caching can be enabled for every compute resource. The code is reusable to plugins or other compute resources can reuse the caching mechanism.
Cache invalidation was not straight forward to implement because I wanted to support memcached so I had to use a "scope" when creating the cache keys. The scope is changed when the cache is invalidated.

Some "benchmarks":

Before:
Completed 200 OK in 16121ms (Views: 15963.0ms | ActiveRecord: 6.4ms)

After:
Completed 200 OK in 1710ms (Views: 1583.8ms | ActiveRecord: 5.1ms)

@mention-bot
Copy link

@timogoebel, thanks for your PR! By analyzing the history of the files in this pull request, we identified @brandonweeks, @mmoll and @shlomizadok to be potential reviewers.

Copy link
Member

@tbrisker tbrisker left a comment

Choose a reason for hiding this comment

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

Looks very good in general, a few comments inline about the code. Couldn't test as I don't have a vmware resource.


def initialize(compute_resource, opts = {})
self.compute_resource = compute_resource
self.cache_duration = opts.fetch(:cache_duration, 180.minutes)
Copy link
Member

Choose a reason for hiding this comment

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

You can use a kwarg here

Copy link
Member

Choose a reason for hiding this comment

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

would it make sense to include some sort of a hourly task that keeps refreshing the cache offline?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I do want to add a hourly rake task for this that can be called by cron. I'd prefer to do this in a separate PR, though.

private

def action_permission
case params[:action]
when 'available_images', 'available_clusters', 'available_flavors', 'available_folders', 'available_networks', 'available_resource_pools', 'available_security_groups', 'available_storage_domains', 'available_zones', 'associate', 'available_storage_pods'
:view
when 'invalidate_cache'
:edit
Copy link
Member

Choose a reason for hiding this comment

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

I think it makes sense to allow viewers to also invalidate the cache (for example if they notice the data seems outdated), this doesn't actually do anything to the compute resource other then reload the data.

@@ -123,7 +137,7 @@ def resource_pools

def action_permission
case params[:action]
when 'associate'
when 'associate', 'invalidate_cache'
Copy link
Member

Choose a reason for hiding this comment

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

ditto

private

def cache
@cache || ComputeResourceCache.new(self)
Copy link
Member

Choose a reason for hiding this comment

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

I think this needs to be ||= for the new cache to be saved

@@ -7,4 +7,6 @@
<%= checkbox_f f, :set_console_password, :checked => f.object.set_console_password?,
:label => _("Console passwords"),
:help_inline => _("Set a randomly generated password on the display connection") %>
<%= checkbox_f f, :caching_enabled, :label => _("Enable caching"),
Copy link
Member

Choose a reason for hiding this comment

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

This parameter should also be added to the api

@@ -0,0 +1,5 @@
class AddCachingEnabledToComputeResource < ActiveRecord::Migration
def change
add_column :compute_resources, :caching_enabled, :boolean
Copy link
Member

Choose a reason for hiding this comment

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

This should have a default false I believe

Copy link
Member

Choose a reason for hiding this comment

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

do you see a need to default to false? I would rather opt in by default, no one wants the slower option unless they have a problem?

@@ -4,6 +4,7 @@
<% title_actions display_link_if_authorized(_("Associate VMs"),
hash_for_associate_compute_resource_path(:compute_resource_id => @compute_resource).merge(:auth_object => @compute_resource, :permission => 'edit_compute_resources'),
:title => _("Associate VMs to Foreman hosts"), :method => :put, :class=>"btn btn-default"),
(display_link_if_authorized(_('Clear Cache'), hash_for_invalidate_cache_compute_resource_path(@compute_resource).merge(:auth_object => @compute_resource), :method => :put, :class => "btn btn-default") if @compute_resource.respond_to?(:invalidate_cache) && @compute_resource.caching_enabled),
Copy link
Member

Choose a reason for hiding this comment

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

nitpick: I would call it reload vs clear cache.

Copy link
Member Author

Choose a reason for hiding this comment

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

How about "refresh cache"?

@@ -6,3 +6,7 @@
<td><%= _("Console passwords") %></td>
<td><%= @compute_resource.set_console_password? ? _("Enabled") : _("Disabled") %></td>
</tr>
<tr>
<td><%= _("Caching") %></td>
<td><%= @compute_resource.caching_enabled ? _("Enabled") : _("Disabled") %></td>
Copy link
Member

Choose a reason for hiding this comment

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

consider using an icon ? from http://www.patternfly.org/styles/icons/#_ maybe pficon-ok and pficon-warning-triangle-o?

Copy link
Member Author

@timogoebel timogoebel Jan 29, 2017

Choose a reason for hiding this comment

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

I actually do prefer the text vs. the icons to be consistent in the UI. We can change this to icons in a separate PR. pficon-warning-triangle-o is too much warning. If a user disables the caching, it won't break anything.

@@ -399,6 +399,7 @@
get 'resource_pools'
post 'ping'
put 'associate'
put 'invalidate_cache'
Copy link
Member

Choose a reason for hiding this comment

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

nitpick: i would prefer reload vs invalidate (sounds scary as we all know cache invalidation is a hard problem ;))

@ohadlevy
Copy link
Member

I would like to see a refresh / reload button on the host edit page, i think this is where you would really need up to date / latest info as you dont have the option (dc, cluster etc).

@timogoebel
Copy link
Member Author

I would like to see a refresh / reload button on the host edit page, i think this is where you would really need up to date / latest info as you dont have the option (dc, cluster etc).

@ohadlevy : Would it be ok for you to add this in a separate PR? I think, this will make coding and reviewing easier.

Copy link
Member

@tbrisker tbrisker left a comment

Choose a reason for hiding this comment

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

A couple more comments inline. As for the naming of the action, "reload" seems to be a bit misleading, as it isn't actually reloaded, rather "cleared" or "flushed" IIUC.


delegate :logger, :to => ::Rails

def initialize(compute_resource:, cache_duration: nil)
Copy link
Member

Choose a reason for hiding this comment

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

I'm afraid required kwargs is supported only in ruby 2.1, so we can't use that yet. I'd suggest making the first parameter a regular argument and just the cache duration a kwarg. Then you can set the default to 180.minutes in the kwarg rather then below, like so:

def initialize(compute_resource, cache_duration: 180.minutes)

@@ -0,0 +1,5 @@
class AddCachingEnabledToComputeResource < ActiveRecord::Migration
def change
add_column :compute_resources, :caching_enabled, :boolean, default: true
Copy link
Member

Choose a reason for hiding this comment

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

Won't this make compute resources that don't support caching appear to have caching enabled?

Copy link
Member Author

Choose a reason for hiding this comment

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

@tbrisker : Yes, it will. But it's not shown in the UI or API. So it figured, it doesn't really matter. Do you see that differently?

Copy link
Member

Choose a reason for hiding this comment

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

ok, makes sense.


def initialize(compute_resource, cache_duration: nil)
self.compute_resource = compute_resource
self.cache_duration = cache_duration || 180.minutes
Copy link
Member

Choose a reason for hiding this comment

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

Instead of defaulting the kwarg to nil then defaulting here to 180.minutes, you can do that in the kwarg itself

@timogoebel
Copy link
Member Author

timogoebel commented Jan 30, 2017

@tbrisker , @ohadlevy : Addressed all of your comments. Thanks a lot for these.

As for the naming of the action, "reload" seems to be a bit misleading, as it isn't actually reloaded, rather "cleared" or "flushed" IIUC.

@tbrisker : Would refresh cache be fine for your opinion? I had clear cache before, but @ohadlevy suggested to use something different.

I currently see these follow up tasks:

  • Add a rake task to refresh the cache.
  • Add a cache refresh button to the select boxed in the host form that flushes the cache and reloads the data.

@tbrisker
Copy link
Member

@timogoebel I guess refresh is better, @ohadlevy what do you think? Still one minor comment on the kwargs, other than that LGTM but I would like someone with access to VMWare to test it as well before merging.

@timogoebel
Copy link
Member Author

@shlomizadok : Would you mind testing this for me? I think a VM show and create should suffice.

@timogoebel
Copy link
Member Author

Caching is now disabled if the compute resource has not been saved yet, fixed the kwarg default and removed caching from dc method as method is quite fast.

@timogoebel timogoebel force-pushed the 13618-vmware-caching branch 2 times, most recently from 0520693 to 4fc0c9f Compare January 30, 2017 16:27
@timogoebel
Copy link
Member Author

Rebased and renamed reload_cache to refresh_cache.

@timogoebel timogoebel force-pushed the 13618-vmware-caching branch 2 times, most recently from d73543a to e8621dc Compare January 31, 2017 07:49
@timogoebel
Copy link
Member Author

Fixed an issue with caching of dc.clusters.

@TheKangaroo: Would you mind testing this PR and let us know if you see any issues? Thanks.

end

def datastores(opts = {})
if opts[:storage_domain]
name_sort(dc.datastores.get(opts[:storage_domain]))
cache.cache(:"datastores-#{opts[:storage_domain]}") do
name_sort(dc.datastores.get(opts[:storage_domain]))
Copy link
Member

Choose a reason for hiding this comment

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

not directly required, but this could benefit from a kwarg for storage domain

@tbrisker
Copy link
Member

Looks good to me pending testing, test failure is unrelated.

@TheKangaroo
Copy link

Hi @tbrisker, I tested it in our environment.
I couldn't find any issues and the runtime improvements in creating hosts is huge :)
I really like your PR @timogoebel

@shlomizadok
Copy link
Member

@tbrisker - testing this now. give me 2 minutes to ack :)

@shlomizadok
Copy link
Member

ACK 👍

@tbrisker tbrisker merged commit 9caab04 into theforeman:develop Jan 31, 2017
@tbrisker
Copy link
Member

Thanks @timogoebel !

@timogoebel
Copy link
Member Author

Created two follow-up tickets:

Cache-Warming rake task:
http://projects.theforeman.org/issues/18314

Refresh from host page:
http://projects.theforeman.org/issues/18315

tbrisker added a commit to tbrisker/foreman that referenced this pull request Dec 5, 2017
After 5 failed attempts from the same ip, login will be blocked for 5
minutes.
tbrisker added a commit to tbrisker/foreman that referenced this pull request Dec 5, 2017
After 30 failed attempts from the same ip, login will be blocked for 5
minutes from that ip.
tbrisker added a commit to tbrisker/foreman that referenced this pull request Dec 5, 2017
After 30 failed attempts from the same ip, login will be blocked for 5
minutes from that ip.
tbrisker added a commit to tbrisker/foreman that referenced this pull request Dec 10, 2017
After 30 failed attempts from the same ip, login will be blocked for 5
minutes from that ip.
lzap pushed a commit that referenced this pull request Dec 11, 2017
After 30 failed attempts from the same ip, login will be blocked for 5
minutes from that ip.
mmack pushed a commit to mmack/foreman that referenced this pull request Dec 13, 2017
After 30 failed attempts from the same ip, login will be blocked for 5
minutes from that ip.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
7 participants