-
Notifications
You must be signed in to change notification settings - Fork 90
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
Platform framework and detect DSL #204
Conversation
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>
Signed-off-by: Jared Quick <jquick@chef.io>
include Train::Platforms::Detect::Linux | ||
include Train::Platforms::Detect::Windows | ||
|
||
def rbconfig(regex) |
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 name as this will be part of what you can use in the detect logic. Maybe "get_host_from_ruby" or something?
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.
How about rbconfig_host_os
or ruby_host_os
? Not a fan of get_
methods personally.
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 like ruby_host_os
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>
3179679
to
7fd444d
Compare
Signed-off-by: Jared Quick <jquick@chef.io>
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.
@jquick this is pretty stellar work for your first time mucking around in Train/InSpec. Nicely done.
I have a bunch of style feedback and questions, and I'm happy to get on a Zoom and talk through them if needed. Ultimately, the structure, concepts, and layout all make sense to me and I'm happy to see them in this state. Great work.
lib/train/platform.rb
Outdated
module Train | ||
class Platform | ||
include Train::Platforms::Common | ||
attr_accessor :condition, :families, :backend, :platform, :family_hierarchy |
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.
Nitpick warning, but could I implore you to sort these alphabetically so, as they grow/shrink, it's easier to find what you're looking for?
lib/train/platform.rb
Outdated
@family_hierarchy = [] | ||
@platform = {} | ||
@detect = nil | ||
@title = name =~ /^[[:alpha:]]+$/ ? name.capitalize : name |
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.
Curious as to why this match is needed. Even if the name is just a number, making it a string and capitalizing it won't throw an error.
Would it be simpler to make it this?: @title = name.to_s.capitalize
lib/train/platform.rb
Outdated
@platform | ||
end | ||
|
||
# Add genaric family? and platform methods to an existing platform |
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.
s/genaric/generic
(at least you know I read the comments, too 🙂 )
lib/train/platform.rb
Outdated
family_list = Train::Platforms.families | ||
family_list.each_value do |k| | ||
next if respond_to?(k.name + '?') | ||
define_singleton_method(k.name + '?') { |
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.
Can we use do ... end
for these blocks that consume multiple lines?
lib/train/platform.rb
Outdated
# Helper methods for direct platform info | ||
@platform.each_key do |m| | ||
next if respond_to?(m) | ||
define_singleton_method(m) { |
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.
Can we use do ... end
for these blocks that consume multiple lines?
def scan_children(parent) | ||
parent.children.each do |plat, condition| | ||
next if plat.detect.nil? | ||
result = instance_eval(&plat.detect) |
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.
Same as above re: unused variable result
with the exception of seeing if it's true
or not.
end | ||
|
||
def scan_family_children(plat) | ||
child_result = scan_children(plat) if !plat.children.nil? |
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.
We should be consistent with our uses of if
and unless
... since you do a bunch of unless blah.nil?
, we should do that here too:
child_result = scan_children(plat) unless plat.children.nil?
lib/train/platforms/family.rb
Outdated
@families = {} | ||
@children = {} | ||
@detect = nil | ||
@title = name =~ /^[[:alpha:]]+$/ ? "#{name.capitalize} Family" : name |
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.
Same question as above re: Platform name/title -- I'm curious as to why this regex match is necessary.
@@ -0,0 +1,456 @@ | |||
# encoding: utf-8 |
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.
Stylistically, this file reads really weird to me because it basically takes action when it's require
d. We don't really do anything else like that without our codebase.
I'm wondering if it would make sense to wrap this in a class/method and call that in lib/train/platforms.rb
For example:
module Train::Platforms
class Specifications
def self.load_specifications
plat = Train::Platforms
plat.family('windows')
.detect # .... etc ....
end
end
end
... and then at the very bottom of lib/train/platforms
:
Train::Platforms::Specifications.load_specifications
Honestly, this file just looks like a left-behind test file even though it's the meat of our data mapping 🙂
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 moved this to a proper class. I decided to load it on the transport creation as we are going to have the API transports require a different set of specifications.
lib/train/transports/local.rb
Outdated
def local? | ||
true | ||
end | ||
|
||
def os |
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 we're not adding any value by having this method defined (i.e. we're not adding a deprecation warning), can we just call alias
instead and alias os
to platform
with a comment added as to why we're doing it (i.e. because InSpec still expects it to be os
).
Same comment applies to all the other Transport classes.
Signed-off-by: Jared Quick <jquick@chef.io>
end | ||
|
||
def unix_file_exist?(path) | ||
@backend.run_command("test -f #{path}").exit_status.zero? | ||
end | ||
|
||
def uname_call(cmd) |
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 is really just run_command
now, rather than uname-specific... maybe we should change the method name and that way it can be used for other things too?
Signed-off-by: Jared Quick <jquick@chef.io>
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.
Great work @jquick I added some questions.
lib/train/transports/docker.rb
Outdated
end | ||
|
||
# we need to keep os as a method for backwards compatibility with inspec | ||
alias os platform |
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.
Should we do this in our base connection? This ensures that it is consistent across all connections and the implementations can focus on using platform
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.
maybe we need a os_transport
then?
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 would be fine, if we are not going to be using BaseConnection for API.
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.
We can also move it to base for now and add a os connection, once we add api
lib/train/transports/docker.rb
Outdated
@@ -56,6 +56,7 @@ def reuse_connection | |||
class Train::Transports::Docker | |||
class Connection < BaseConnection | |||
def initialize(conf) | |||
Train::Platforms::Specifications::OS.load_specifications |
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.
Should we move this to base connection?
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 reason it was done on a per transport level was that we will likely have a Train::Platforms::Specifications::API.load_specifications
for http and api transports. I don't think we want to load the OS for all transports including API ones.
That is if we decide to sub the BaseConnection for API as well. Maybe we make a new one for that.
@@ -55,10 +56,13 @@ def close | |||
@session = nil | |||
end | |||
|
|||
def os | |||
@os ||= OS.new(self) | |||
def platform |
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 the method calls are more similar now, we could move that to base connection too?
@@ -0,0 +1,56 @@ | |||
# encoding: utf-8 | |||
|
|||
require 'train/platforms/detect/os_linux' |
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.
It feels like os_common.rb
, os_linux.rb
and os_windows.rb
are just detect helper, the actual detection is done with the specifications. Am I right?
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 is correct, they are just helper methods that can be used inside the detection blocks.
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.
Should we make this more clear in our naming?
# start with the platform/families who have no families (the top levels) | ||
top = Train::Platforms.top_platforms | ||
top.each do |_name, plat| | ||
next unless plat.detect |
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.
Should we implement a method detect
in family.rb
? This would abstract the issue for us here. Also I am not sure if we want to use lambda for detect, so that we do not need to call instance_eval
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 have added the false lambda instead of the check for detect. This way everything can be evaluated accordingly.
As far as moving away from instance_eval/exec. The reason we are doing this is so the detect logic will have access to all the helper methods (os_common, os_linux, etc...) in the detect context. We may be able to require all this logic in each instance but that seems overkill for the memory and really doing the same thing under the hood. This also makes it easy to create custom platforms on the fly via inspec or other instances. After talking it over and due to its controlled nature we are voting to keep it for now. I can comment it up to explain a bit more in code.
lib/train/platform.rb
Outdated
@@ -0,0 +1,80 @@ | |||
# encoding: utf-8 |
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.
Should this file not be located in lib/train/platforms/platform
?
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.
Yeah, I do think that should be moved in after thinking about it.
Signed-off-by: Jared Quick <jquick@chef.io>
83e3599
to
453a51d
Compare
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>
d76d0f4
to
babc875
Compare
Signed-off-by: Adam Leff <adam@leff.co>
This change moves the detect logic for platforms into a new framework. You can create platforms on the fly using the new platform DSL. There are still some detect tests to write for specific platforms.
For more info about this RFC please visit inspec/inspec#1661