-
Notifications
You must be signed in to change notification settings - Fork 683
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 rabbitmq_config
resource
#1639
Conversation
dfc925f
to
52a6b0d
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.
Thank you @arlimus This is awesome. I added a note regarding Windows support, since the configuration is also available on Windows machines
name 'rabbitmq_config' | ||
desc 'Use the rabbitmq_config InSpec resource to test configuration data '\ | ||
'for the RabbitMQ service located in /etc/rabbitmq/rabbitmq.config on '\ | ||
'Linux and UNIX platforms.' |
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.
Is there any reason why Windows rabitmq configurations cannot be parsed?
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.
Good point! Not at all actually, just haven't implemented default paths for Windows yet.
'for the RabbitMQ service located in /etc/rabbitmq/rabbitmq.config on '\ | ||
'Linux and UNIX platforms.' | ||
example " | ||
describe rabbitmq_config.params('rabbit', 'ssl_listeners') do |
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 params
to be established as a pattern to retrieve all values for all configuration files
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.
yes please 😁
" | ||
|
||
def initialize(conf_path = nil) | ||
@conf_path = conf_path || '/etc/rabbitmq/rabbitmq.config' |
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.
Are we going to supports the default per OS? See https://www.rabbitmq.com/configure.html#configuration-file
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 idea, let's add that in the next 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.
This is a heck of a change. Nothing I have is a blocker but it would probably good to add some more detail to the #to_s
method as described. Otherwise, I say we ship it and see what we uncover in the field.
lib/resources/rabbitmq_conf.rb
Outdated
end | ||
|
||
def to_s | ||
'RabbitMQ Configuration' |
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 include @conf_path
here so it's clear in the output what config file we read from? Thinking about the use case where a user is reading multiple RabbitMQ config files. We do this pattern with mysql_conf, etc.
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.
Will do, thank you! (curious, I didn't see it in mysql_conf.rb
, but it is used in pip, x509 etc)
private | ||
|
||
def read_content | ||
return @content if defined?(@content) |
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've been bitten enough times by defined?
not returning what I expect it to that I usually follow the pattern of return @content unless @content.nil?
in these situations. Not a blocker, just something to consider...
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 I started to use this convention initially was to avoid queries to the system for files that might be nil
. It typically happens with missing permissions, permission the file read may be attempted a large number of times. It is only meant as an optimization.
That said, this part as well as the pieces below really need to be abstracted away, since these steps are used frequently.
lib/resources/rabbitmq_conf.rb
Outdated
end | ||
|
||
@content = file.content | ||
if @content.empty? && !file.empty? |
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 what situation would cause one of these to be true
while the other is false
...
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.
Good catch, I copied this from another resource and will remove it.
We had this case in the past, when files would return an empty string due to missing permissions (and in line with serverspec behavior) on some transport connections. We seem to have unified this in train now, so it is not needed anymore. Thank you!
lib/resources/rabbitmq_conf.rb
Outdated
return @params = {} if read_content.nil? | ||
lex = ErlangParser.new.parse(read_content) | ||
tree = ErlangTransform.new.apply(lex) | ||
@params = turn_to_hash(tree) |
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 imagine this is going to be a pretty common need... should we instead make a #to_h
method inside the ErlangTransform
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.
Good idea, we might need a small class in between. That hash-conversion only works with a Array-Tuple combination, which is typical for RabbitMQ files. If we use this in other places the syntax might be very different. I'll add it to another class that abstracts the parser and transformer away
Signed-off-by: Dominik Richter <dominik.richter@gmail.com>
52a6b0d
to
02e435b
Compare
Looks good to me, @arlimus! If @chris-rock is good with it, I'm good. Let's just squash down to a single commit (which we can do via GitHub squash-and-merge, you don't actually have to do it... and thank you for adding incremental commits, makes it SO much easier to review). |
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.
Cool @arlimus Lets add Windows support in another PR.
rabbitmq_config
This PR introduces the
rabbitmq_config
resource. It parses the full configuration file and represents it internally as a hash that can be accessed for InSpec tests.It may require a bit more alignment with other resources and some optimization. (also recognizing more shared patterns)
implications
There is 2 large implications with this move:
parslet
gem as a dependency1. Adding a complex parser to the core may require more effort down the line. I'm happy with the way it turned out in the end, but I'm aware that the underlying mechanism still carries a number of corner-cases we must be mindful of. They may only apply to very few use-cases (or put differently: all config files I ever used have been tested well), but it may bite us. The best example of this was the inclusion of parsing bit-streams (took 50% of the parser code)
2. Adding parslet a 78k ruby lib without any additional dependencies (which we already have in our dependency tree! see edit below). The implication is to have this library available for other rather complex config files, including Nginx, Apache, HCL, and custom configs.
I investigated treetop, parslet, and citrus, all of which are great for this task. Of those, parslet is actively maintained with recent contributions a large community. It also functions fully in Ruby without creating dynamic classes.
This may become a great foundation for other parsers down the line. What do you think?
edit: Apparently TOML already requires parslet! The dependency is rather outdated (3years+). I went down a few versions to prevent conflicts and might take a stab at the toml lib.