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

Enable caching for backend calls #2309

Merged
merged 9 commits into from
Dec 4, 2017
Merged

Enable caching for backend calls #2309

merged 9 commits into from
Dec 4, 2017

Conversation

jquick
Copy link
Contributor

@jquick jquick commented Nov 15, 2017

This PR enables caching for all calls to the train backend. Currently this is set on the profile level. This was inspired by @sdelano and his work via #2158

Signed-off-by: Jared Quick jquick@chef.io

@jquick jquick requested a review from a team as a code owner November 15, 2017 18:33
@jquick jquick changed the title Enable caching for for backend calls Enable caching for all backend calls Nov 15, 2017
@jquick jquick changed the title Enable caching for all backend calls Enable caching for backend calls Nov 15, 2017
Copy link
Contributor

@adamleff adamleff left a comment

Choose a reason for hiding this comment

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

This is a great first pass, @jquick! I have some questions and some cleanup items.

@@ -124,6 +127,10 @@ def version
metadata.params[:version]
end

def cache_resources?
metadata.params[:cache_resources] || false
Copy link
Contributor

Choose a reason for hiding this comment

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

|| logic with default boolean values always makes me nervous. If someone decides to make this default behavior and just changes the false to true, it will never be able to be set to false:

[1] pry(main)> a = true
=> true
[2] pry(main)> a || true
=> true
[3] pry(main)> a = false
=> false
[4] pry(main)> a || true
=> true

To avoid a silly regression like that, how about we change this to use #fetch instead?

metadata.params.fetch(:cache_resources, false)


module Inspec
class Transport
attr_accessor :cache_resources, :conn
Copy link
Contributor

Choose a reason for hiding this comment

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

Unless it's necessary, I'd rather we didn't abbreviate variable names. (I know we just did it in the Train platforms PR - i.e. plat instead of platform - but it still bugs me 🙂 )

Any reason this shouldn't be connection?

alias platform os

# This is needed for the mock connection which has some
# unique method calls
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we provide an example or two in the comment as to the type of method calls we're catching here, deeming this necessary?

if @cache_resources == true && @cmd_cache.key?(cmd)
@cmd_cache[cmd]
elsif @cache_resources == true
Inspec::Log.warn('running raw command and caching')
Copy link
Contributor

Choose a reason for hiding this comment

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

These should be debug messages, no?

Inspec::Log.warn('running raw command and caching')
@cmd_cache[cmd] = @conn.run_command(cmd)
else
Inspec::Log.warn('running raw command')
Copy link
Contributor

Choose a reason for hiding this comment

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

Debug instead of warn?


describe 'create train connection' do
it 'return new train transport' do
trans = transport
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the purpose of assigning this to a new variable? This happens throughout the tests, so I'm not going to comment on all of them, but I'm curious as to why it's necessary.

it 'check mock_os method' do
trans = transport
os = trans.mock_os({ name: 'mock'})
os.must_be_kind_of Train::Transports::Mock::Connection::OS
Copy link
Contributor

Choose a reason for hiding this comment

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

Should probably also check that os[:name] == 'mock' here to properly exercise the mock_os method.


it 'load file with caching' do
trans = transport
trans.instance_variable_set(:@cache_resources, true)
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't cache_resources an attr_accessor? I like to avoid setting/getting instance variables unless necessary. I think we can just change this to:

transport.cache_resources = true


it 'run command with caching' do
trans = transport
trans.instance_variable_set(:@cache_resources, true)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above re: using the attr_accessor on the transport.

@jquick
Copy link
Contributor Author

jquick commented Nov 15, 2017

@adamleff - Thanks for the feedback. I think I have those items resolved.

@chris-rock
Copy link
Contributor

This is a great improvement @jquick and a very good start for a discussion!

After thinking for a while, I came to the conclusion that it would be best to implement a CacheConnection in train that would take another connection as initialize argument. This would solve multiple problems:

  • every train user can use it, not just inspec
  • the decision is still up to the train user if he wants to use caching or not
  • InSpec will just use the cache connection for normal execution, but not for shell

This also means we should clean up the simple caching as we have it in train: https://github.com/chef/train/blob/master/lib/train/transports/docker.rb#L73-L80

@jquick
Copy link
Contributor Author

jquick commented Nov 17, 2017

@chris-rock - Thanks for the feedback. I will move the caching to Train. How do you feel about keeping the toggle here to enable/disable on the profile level?

@adamleff
Copy link
Contributor

Moving it to Train seems totally fine to me, too. I still think we need to keep the toggle here on the InSpec side to allow the InSpec profile author to opt-in to the caching, and the InSpec will use the proper Train transport accordingly.

@@ -1,9 +1,4 @@
# encoding: utf-8
# copyright: 2015, Dominik Richter
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you cannot remove the copyright, since it stays available. This was developed by Dom before it was acquired by Chef

@@ -32,7 +27,7 @@ def to_s

# Ruby internal for pretty-printing a summary for this class
def inspect
"Inspec::Backend::Class @transport=#{backend.class}"
"Inspec::Backend::Class @transport=#{@backend.connection.class}"
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we do not need this here anymore

Copy link
Contributor

@chris-rock chris-rock left a comment

Choose a reason for hiding this comment

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

Nice cleanup @jquick I think we should not leave it to the profile author if caching is enabled or not. This is a decision of the runtime. We may decided to leave caching of for now but for InSpec 2.0 we may turn this on by default.

@@ -124,6 +126,10 @@ def version
metadata.params[:version]
end

def cache_resources?
metadata.params.fetch(:cache_resources, false)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should not make the caching part of the inspec.yml since this is static content. From my perspective, this needs to be a flag for inspec cli where by default caching is turned off

@jquick
Copy link
Contributor Author

jquick commented Nov 27, 2017

This should be set. Flag was set to --backend-cache/--no-backend-cache as --cache was already taken for profile caching on exec. Open to any other name though.

@@ -15,6 +15,8 @@ def self.target_options
desc: 'Choose a backend: local, ssh, winrm, docker.'
option :host, type: :string,
desc: 'Specify a remote host which is tested.'
option :backend_cache, type: :boolean,
Copy link
Contributor

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 call it cache

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe we set the default here? default: false,

Copy link
Contributor

@adamleff adamleff left a comment

Choose a reason for hiding this comment

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

I'd like to discuss this PR in more depth, perhaps after standup today. Comments in-line. Also, we cannot merge this until Train has a released version that supports the enable/disable calls. At that time, this PR will need to be updated to include a gemspec update so we properly depend on a version of Train that supports the feature.

define_method :backend do
if @cache_resources
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there another place we can/should put the enable_cache calls? The way I read this, every time something in InSpec calls for the backend it will send these methods to the Train connection. That could happen a LOT.

Maybe we just need an enable/disable method on the backend itself that can be called once when appropriate?

Also, we're making an assumption here that caching is disabled by default in Train, which is half correct -- we always cache files, and don't provide a way to disable currently. Should this have an else statement where we disable the cache?

This probably warrants further discussion after standup... until Train is consistent with the default behavior of both files and commands, we may want to consider only manipulating the command cache for now and then deal with files later.

@jquick
Copy link
Contributor Author

jquick commented Nov 27, 2017

Please note: test will bomb until we upgrade train with the caching changes

Copy link
Contributor

@adamleff adamleff left a comment

Choose a reason for hiding this comment

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

One last question regarding the caching settings conditional and we should be good to go.

elsif config[:debug_shell]
connection.disable_cache(:file)
connection.disable_cache(:command)
elsif !config[:backend_cache] && config[:backend] != :mock
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you explain why this can't be an else? It's not quite clear to me. And probably warrants a code comment explaining the condition (i.e. why the mock backend is special here).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I'll add a comment. Basically the mock transport uses the base connection caching also. So we never want to disable it. We hard set the cache values for testing and usually bypass thor so it would always be false. It actually may be cleaner to put the mock check on the enable and just ensure its enabled.

Copy link
Contributor

Choose a reason for hiding this comment

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

What would happen in the mock transport if it was disabled? Slower tests? If so, by how much?

Copy link
Contributor Author

@jquick jquick Nov 27, 2017

Choose a reason for hiding this comment

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

Not really, you cant actually run file/command calls via mock without preloading it. Else it will just fall to errors. So for the core of MockTransport to work caching is always needed. Ex:
https://github.com/chef/train/blob/master/lib/train/transports/mock.rb#L139

We hard code it during the transport creation but this would override it.

Copy link
Contributor

@adamleff adamleff left a comment

Choose a reason for hiding this comment

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

Conditionally approved. Before we merge:

  • a new version of Train needs to be released
  • this PR needs to be updated with a gemspec pin update for the train gem
  • tests go green

Nice work, @jquick!

connection.disable_cache(:file)
connection.disable_cache(:command)
else
connection.disable_cache(:command)
Copy link
Contributor

Choose a reason for hiding this comment

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

should we explicitly enable file caching? so we do not depend on train defaults?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added

Copy link
Contributor

@chris-rock chris-rock left a comment

Choose a reason for hiding this comment

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

Great improvement @jquick

@jquick jquick force-pushed the jq/backend_caching branch 3 times, most recently from 44dbc93 to 6baa01a Compare December 4, 2017 17:49
@jquick
Copy link
Contributor Author

jquick commented Dec 4, 2017

This is tested and looks good. We wont have as good windows caching until #2368 is merged. It would be nice to rebase this again after that is merged and make sure my numbers match up.

Signed-off-by: Jared Quick <jquick@chef.io>
Signed-off-by: Jared Quick <jquick@chef.io>
Signed-off-by: Jared Quick <jquick@chef.io>
Signed-off-by: Jared Quick <jquick@chef.io>
Signed-off-by: Jared Quick <jquick@chef.io>
Signed-off-by: Jared Quick <jquick@chef.io>
Signed-off-by: Jared Quick <jquick@chef.io>
Signed-off-by: Jared Quick <jquick@chef.io>
@jquick
Copy link
Contributor Author

jquick commented Dec 4, 2017

Confirmed the cache timings on various windows and unix systems. This looks good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants