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 rpm_dbpath support to the package resource #1960

Merged
merged 1 commit into from
Jun 28, 2017
Merged

Add rpm_dbpath support to the package resource #1960

merged 1 commit into from
Jun 28, 2017

Conversation

jerryaldrichiii
Copy link
Contributor

@jerryaldrichiii jerryaldrichiii commented Jun 23, 2017

This adds support for querying a specific RPMDB

Example:

describe package('my_package', rpm_dbpath: '/var/lib/my_rpmdb') do
  it { should be_installed }
end

Fixes #1959

@jerryaldrichiii jerryaldrichiii requested review from nsdavidson and removed request for nsdavidson June 23, 2017 08:06
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.

This looks really great @jerryaldrichiii I just added a suggestion for a minor improvement

@dbpath = opts.fetch(:rpm_dbpath, nil)
end

def rpm_command(package_name)
Copy link
Contributor

Choose a reason for hiding this comment

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

that should be a private function of that class

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed. I'll make the change now!

chris-rock
chris-rock previously approved these changes Jun 23, 2017
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.

Awesome, very quick turn-around @jerryaldrichiii

@chris-rock chris-rock requested a review from adamleff June 23, 2017 10:19
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.

@jerryaldrichiii this is a great contribution, thank you!

My main concern is the one that I raised with you directly regarding returning false if the RPM DB cannot be found. We've already seen similar situations confuse our users (i.e. returning nil file contents simply because the InSpec user didn't have permissions to read, but not giving them that feedback). In this case, we'd return false but if they log in manually and poke around, they'd see it's installed. Ideally, we'd be able to raise an exception and provide the user with more helpful error messaging, but until we implement #1205, our best option is to skip_resource.

Since you can't skip_resource in an object that's not an Inspec::Resource, you need to handle this in the top-level of the resource. Take a look at the missing_requirements pattern in the host resource:

https://github.com/chef/inspec/blob/master/lib/resources/host.rb#L68-L71
https://github.com/chef/inspec/blob/master/lib/resources/host.rb#L136-L140
https://github.com/chef/inspec/blob/master/lib/resources/host.rb#L182-L190

I'd love to see something like that implemented for this before we merge. Then, after #1205 is implemented, we can change that skip_resource into an exception that either skips or fails the test as necessary. I'm happy to pair with you if needed.

@jerryaldrichiii
Copy link
Contributor Author

jerryaldrichiii commented Jun 25, 2017

Great feedback @adamleff and thank you for the reference material!

I added something similar by doing the following:

  • Create a list for missing_requirements so Inspec::Resources::Package can support multiple reasons for skipping a test
  • Add a private method to Inspec::Resources::Package to evaluate missing requirements (allowing for multiple reasons to skip the resource)
  • Add a specific evaluator for @pkgman missing requirements (this sets a pattern for others going forward)
  • Add a public missing_requirements method to Inspec::Resources::Rpm which allows for more than one argument to be validated going forward
  • Add a private validate_arguments method Inspec::Resoruces::Rpm to append missing requirements to the missing_requirements list for command arguments
  • Add a private validate_rpm_dbpath method Inspec::Resoruces::Rpm to append missing requirements to the missing_requirements list specific to the --dbpath command line argument
  • Modify the Unit tests to match Minitest patterns (no context available like RSpec). NOTE: Technically this describe block should move to another file since it is separate from the Inspec::Resources::Package module

@chris-rock chris-rock dismissed their stale review June 26, 2017 04:45

Implementation changed

@jerryaldrichiii
Copy link
Contributor Author

@adamleff, I took your offline feedback and made some modifications.

Now the PkgManagement class has a missing_requirements method that the inheriting classes can use. This removes that defined? logic.

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.

@jerryaldrichiii this is much closer to what I'd like to see! I think there's a couple of small clean-up things we can do and then this will be good to go.

@@ -44,8 +44,10 @@ def initialize(package_name = nil) # rubocop:disable Metrics/AbcSize
elsif ['hpux'].include?(os[:family])
@pkgman = HpuxPkg.new(inspec)
else
return skip_resource 'The `package` resource is not supported on your OS yet.'
skip_resource 'The `package` resource is not supported on your OS yet.'
Copy link
Contributor

Choose a reason for hiding this comment

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

You probably want to leave the return here - there's no reason to continue to evaluating missing requirements if the resource isn't supported on the target OS.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, will fix!

end

evaluate_missing_requirements(@pkgman.missing_requirements) if @pkgman
Copy link
Contributor

Choose a reason for hiding this comment

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

If you leave the return above, you'll always have a populated @pkgman variable, so I'd just remove if @pkgman

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, since the pkg manager is stored in an instance variable, you probably don't need to pass it. Just let evaluate_missing_requirements take zero arguments and it can refer to @pkgman by itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, will fix!


private

def evaluate_missing_requirements(missing_requirements)
Copy link
Contributor

Choose a reason for hiding this comment

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

You want to bail out of a method as quickly as possible if you can. In this case, you build up a skip_msg that you may never use because you don't check for emptiness of the missing requirements until the very last step.

I'd rewrite this method like this:

def evaluate_missing_requirements
  missing_requirements = @pkgman.missing_requirements
  return if missing_requirements.empty?

  skip_resource "The following requirements are not met for this resource: #{missing_requirements.join(', ')}"
end

I don't know that you need to compact and uniq unless you're doing something in your code that you think would require that... in which case I'd encourage you to solve that problem since you control the whole kit and kaboodle. 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, will fix!


private

def validate_arguments
Copy link
Contributor

Choose a reason for hiding this comment

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

It feels like this method and the one below it are unnecessary layers of abstraction. Any reason not just to fold these into missing_requirements in the Rpm class? If we collect additional requirements later, we can break those down until separate methods but it feels like a bunch of hopping around between methods to get to a simple "if this parameter isn't nil, check to make sure it's actually a file on disk" check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, will fix!

Signed-off-by: Jerry Aldrich III <jerry@chef.io>
@jerryaldrichiii
Copy link
Contributor Author

@adamleff I pushed up my recent changes based on your feedback.

Keep it coming!

@adamleff
Copy link
Contributor

Looks great, @jerryaldrichiii - thanks!

@adamleff adamleff added the Type: Enhancement Improves an existing feature label Jun 27, 2017
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 addition @jerryaldrichiii


private

def evaluate_missing_requirements
Copy link
Contributor

Choose a reason for hiding this comment

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

While I agree that we need to find a pattern for checking missing options, the current approach feels bloated and very complicated. I'd like to replace this with a version that is more lightweight and more flexible to be used in all resources. I do not have an idea right now, therefore this is not a PR blocker.

@chris-rock chris-rock merged commit cc6f1e9 into inspec:master Jun 28, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Enhancement Improves an existing feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants