-
Notifications
You must be signed in to change notification settings - Fork 897
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 rake script to export/import miq alerts and alert profiles #14126
Conversation
@branic First off, thanks for all of this! Just wanted to state that so you know that my comments below don't reflect that we don't appreciate all of this work 😄
|
Thanks for the comments @Fryguy. This first commit was just a straight copy of the files as they exist in the rhconsulting github. I'll work on cleaning up based on your comments and the Rubocop issues. The commented code is from keeping old code when the code changed and I can remove them as part of the cleanup effort. Are additional commits to this PR ok for the cleanups? |
I think comments will come as the code progresses. I think the best approach to get this in faster and easier might be to slim this down to, say, only one of the import scripts + the accompanying helper modules. A 1700+ line PR is almost guaranteed to take a long time. However, if you trim it down to just one script, then we can iterate the review process on just that script, uncovering all of the various comments, and get it in quickly. Once it's in, now you have a foundation for more rake tasks (probably one per PR) and since all of the comments have been already iterated on and discussed, getting these new PRs in will be a LOT faster. |
Yes, that is preferable |
@Fryguy I've removed all but the script to export/import alerts and the two helper modules from this PR. There has been some re-factoring to get rid of references to rhconsulting and general cleanup. I'm not sure what the best way to fix the last of the rubocop offenses. Hopefully this makes it easier to review and can be used as a model for getting the other rake scripts added (in seperate PR's). All feedback is appreciated. |
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'm thinking these helper classes should probably be namespaced a bit. Maybe Vmdb::Serializer::Alert
(naming is hard). That would allow us to create a new Vmdb::Serializer
for whatever we needed to add. Then common functionality like the illegal character and option parsing can go in the Vmdb::Serializer
module itself. Then they would live in lib/vmdb/serializer.rb
and lib/vmdb/serializer/alert.rb
.
Judging from the amount of common code here, it feels like we could do even better with the design, but we can see how it evolves from there. What do you think @Fryguy ?
@@regex_remove_spaces = %r{[/| ]} | ||
|
||
# Replacement character | ||
@@replacement = '_' |
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.
These class variables should be constants.
@@ -0,0 +1,100 @@ | |||
# @class EvmExportImportOptions | |||
# @brief Simple class to parse options passed in to a rake task. | |||
class EvmImportExportOptions |
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 class can probably be replaced by Trollop using the rake task options like
manageiq/lib/tasks/evm_dba.rake
Line 73 in 02c1f12
opts = Trollop.options(EvmRakeHelper.extract_command_options) do |
require_relative 'evm_import_export_illegal_chars' | ||
require_relative 'evm_import_export_options' | ||
|
||
class EvmImportExportAlerts |
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.
These classes should probably live in lib/task_helpers.
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.
A few of these comments apply to multiple places. I want to make suggestions about deduplicating some logic, but I'm not sure what will be common to all of the objects that you want to eventually add so I'll hold off for now.
lib/task_helpers/imports/alerts.rb
Outdated
module TaskHelpers | ||
class Imports | ||
class Alerts | ||
class ParsedNonDialogYamlError < StandardError; end |
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.
Where does this get used? I don't see it in any of these files. If it is used it should live in one place rather than in every 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.
This class is defined in all of the rhconsulting rake scripts, but only used in one of them. I'll remove this class as it is not used.
lib/task_helpers/exports.rb
Outdated
Trollop.die :directory, 'Destination directory must already exist' unless File.directory?(options[:directory]) | ||
Trollop.die :directory, 'Destination directory must be writeable' unless File.writable?(options[:directory]) | ||
|
||
options.delete_if { |_k, v| v.nil? || v == 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.
I'm not sure why this is needed.
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 think it is necessary either. It came as part of the copying code from https://github.com/ManageIQ/manageiq/blob/22efb0914107963b95e064c9d7adb2aa6d905e2a/lib/tasks/evm_dba.rake for Trollop.
|
||
private | ||
|
||
def export_alert_sets(options) |
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 doesn't need to be a separate method if the options are getting passed right through from #export
.
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.
Agreed. I'll change it.
alertsets = YAML.load_file(fname) | ||
import_alert_sets(alertsets) | ||
end | ||
end |
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.
Dir.glob
will work if given a file name, so this can be simplified:
glob = File.file?(options[:source]) ? options[:source] : "#{options[:source]}/*.yaml"
Dir.glob(glob) do |fname|
alertsets = YAML.load_file(fname)
import_alert_sets(alertsets)
end
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.
Makes sense. I'll change to the simplified version.
lib/task_helpers/exports.rb
Outdated
# @param [Hash] options If options[:keep_spaces] == true, then keep spaces in | ||
# \p str , otherwise replace spaces. (default = false, replace spaces) | ||
def self.replace_chars(str, options = {}) | ||
if options.key?(:keep_spaces) && options[:keep_spaces] == true |
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.
A hash will return nil
for a key that doesn't exist, so you don't need this check.
You can just check if options[:keep_spaces]
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.
Changed this as well.
lib/task_helpers/exports.rb
Outdated
# @param [String] str string to replace | ||
# @param [Hash] options If options[:keep_spaces] == true, then keep spaces in | ||
# \p str , otherwise replace spaces. (default = false, replace spaces) | ||
def self.replace_chars(str, options = {}) |
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 feel like if this had a better name we wouldn't need the comment.
Maybe something like safe_filename
?
Also it would document itself better if we passed the option specifically rather than passing the whole options hash for one value. Then the method would look like def self.safe_filename(filename, keep_spaces = false)
which is a lot more clear.
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.
Agreed. I'll change the method name and definition.
@carbonin I've made the changes you requested. I've also adjusted the error handling and added some error handling when performing the imports. |
options | ||
end | ||
|
||
def self.validate_directory(directory) |
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 think all of this should be done right after parsing the options.
Also this might work better if it just returned the string then you could do something like:
error = validate_directory(options[:directory])
Trollop.die :directory, error if error
Then you don't have to write to standard out and you also don't need to define the exceptions.
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 changed this as suggested.
lib/task_helpers/exports.rb
Outdated
end | ||
|
||
def self.validate_directory(directory) | ||
unless directory |
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 think this check is necessary because directory is a required argument.
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 think the only other thing would be some specs. It would be great to see tests at least for the Exports.safe_filename
and the validate_*
methods.
Ideally we would have tests around the whole thing with simple data files to import from and export to. Then we would compare the output against the "right" answer ...
I've added tests for the safe_filename method, but I could use some guidance on how to handle the tests for the validate_* methods if you have any ideas or can point me to some sample code. Also, I had to rebase my branch to be able to get a working environment which looks like it messed up the commit logs and such. I'm not sure how to fix this or what I need to do. As always any help and feedback is appreciated. |
@@ -0,0 +1,44 @@ | |||
describe '#safe_filename' 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.
The top level block here should be:
describe TaskHelpers::Exports do
...
end
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.
Ok. Changed.
lib/task_helpers/exports.rb
Outdated
module TaskHelpers | ||
class Exports | ||
def self.new_filename(filename, keep_spaces = false) | ||
new_filename = filename |
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 looks like you changed the method name and the variable name here @branic
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.
Also, this particular line isn't needed because String#gsub
returns a copy.
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.
Oops I did change both trying to be too efficient with search and replace.
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 had that line because the gsub returned nil if keep_spaces was true. I've changed the code to eliminate this assignment by using a ternary operator.
lib/task_helpers/exports.rb
Outdated
new_filename = filename | ||
new_filename = new_filename.gsub(%r{[ ]}, '_') unless keep_spaces | ||
new_filename = new_filename.gsub(%r{[/]}, 'slash') | ||
new_filename.gsub(%r{[|]}, 'pipe') |
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 think you should be able to combine these by using a hash as the second parameter (see https://ruby-doc.org/core-2.3.3/String.html#method-i-gsub)
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 missed that when I read the doc page the first time. I've changed to use a hash.
export_dir = options[:directory] | ||
|
||
MiqAlertSet.order(:id).all.each do |a| | ||
# Replace characters in the description that are not allowed in filenames |
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 think we need this comment
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 removed the comment.
lib/tasks/evm_export_import.rake
Outdated
task :alertprofiles => :environment do | ||
options = TaskHelpers::Imports.parse_options | ||
TaskHelpers::Imports::AlertSets.new.import(options) | ||
end |
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.
Does this task need the exit
also?
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.
You are correct. I've added the missing line.
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.
Just one minor nit with the specs.
I'm okay with this. I would really like the main import/export methods to also have specs, but that may be asking a bit much for the first pass.
I'll leave the final determination to @Fryguy though.
@@ -0,0 +1,44 @@ | |||
describe TaskHelpers::Exports do | |||
context 'with filename' 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.
This should probably be a describe ".safe_filename" do
The convention in rspec is to describe
the class/module under test then describe
each method you are testing then use it ".." do
blocks for each test case on a particular method.
Then context
can be used for shared setup between it
or describe
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.
That makes sense. I'll add another describe block for the method.
I'd like to be able to have tests for the import/export methods (and maybe even the rake tasks), but I'm not sure how to setup the tests so I need to do some more research in how to create a file to import and write and test the export within RSpec. |
I've thought about using FakeFS [1] to be able to temporarily create the files for the RSpec tests, but the gem isn't included in ManageIQ and I don't know if a gem should be brought in just for running tests. |
I'm ok with a gem that's just for tests. Just be sure to put it into the test group in the Gemfile. |
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.
Looks great! Just one other comment.
@@ -0,0 +1,54 @@ | |||
describe 'TaskHelpers::Imports::AlertSets' 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.
This should be a constant, not a string.
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.
Ugh, I thought i got all of those. It's fixed now.
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.
Looks great @branic. Will merge when it goes green 😄
Some comments on commits https://github.com/branic/manageiq/compare/1c2d26a1930bfa362d928bcb0a9d09c60cf5a976~...042108573513b66e81121cc09e71febffbafa885 lib/task_helpers/imports/alert_sets.rb
lib/task_helpers/imports/alerts.rb
|
Checked commits https://github.com/branic/manageiq/compare/1c2d26a1930bfa362d928bcb0a9d09c60cf5a976~...042108573513b66e81121cc09e71febffbafa885 with ruby 2.2.6, rubocop 0.47.1, and haml-lint 0.20.0 |
@branic Can you modify the description of this PR to match the object type that is supported with the final version of the PR. I would also suggest creating a git issue with a check list to track all the of the types so we can link to the PRs and check them off as we go. |
@gmcculloug I've updated the description as well as opened an issue to track all of the object types. |
These rake scripts and classes provide functionality for exporting/importing of the following ManageIQ object types:
This PR also sets up the framework for future export/import PRs for other ManageIQ object types.
These scripts are based on the CFME RH Consulting Scripts and are used by Red Hat consultants to enable storing customizations in Git and maintaining customizations between environments (e.g. dev/qa/prod) for an SDLC lifecycle.
PR 112 in manageiq-appliance is dependant on this PR and provides a bash script wrapper for these rake scripts.