diff --git a/bin/running-sushi b/bin/running-sushi index c6e1491..e3f53f6 100755 --- a/bin/running-sushi +++ b/bin/running-sushi @@ -16,6 +16,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# rubocop:disable Style/AccessorMethodName, Style/RedundantReturn, GlobalVars require 'chef_diff/repo/svn' require 'chef_diff/repo/git' @@ -29,8 +30,6 @@ require 'optparse' require 'logger' require 'json' -# rubocop:disable GlobalVars - class ChangeProxy attr_accessor :full_name @@ -82,7 +81,7 @@ end def read_checkpoint RunningSushi::Log.debug("Reading #{checkpoint_path}") - File.exists?(checkpoint_path) ? File.read(checkpoint_path).strip : nil + File.exist?(checkpoint_path) ? File.read(checkpoint_path).strip : nil end def node_checkpoint_path @@ -97,14 +96,13 @@ end def read_node_checkpoint RunningSushi::Log.debug("Reading #{node_checkpoint_path}") - if File.exists?(node_checkpoint_path) - upload_checkpoint = JSON.parse(File.read(node_checkpoint_path)) - checkpoint = upload_checkpoint[0] - nodes = upload_checkpoint[1] - return checkpoint, nodes - else - return nil, [] - end + + return nil, [] unless File.exist?(node_checkpoint_path) + + upload_checkpoint = JSON.parse(File.read(node_checkpoint_path)) + checkpoint = upload_checkpoint[0] + nodes = upload_checkpoint[1] + return checkpoint, nodes end def get_pod_config @@ -149,7 +147,7 @@ def chef_upload(knife, repo, checkpoint, local_head) role_local_dir: role_local_dir, role_dir: - RunningSushi::Config.role_path, + RunningSushi::Config.role_path ) rescue ChefDiff::Changeset::ReferenceError RunningSushi::Log.error('Repo error, invalid revision, exiting') @@ -161,12 +159,12 @@ def chef_upload(knife, repo, checkpoint, local_head) x.status == :modified || x.status == :created end deleted_roles = changeset.roles.select do |x| - x.status == :deleted + x.status == :deleted end added_roles = changeset.roles.select do |x| x.status == :modified || x.status == :created end - deleted_roles_local = changeset.roles_local.select { |x| x.status == :deleted } + deleted_roles_local = changeset.roles_local.select { |x| x.status == :deleted } added_roles_local = changeset.roles_local.select do |x| x.status == :modified || x.status == :created end @@ -189,11 +187,11 @@ def chef_upload(knife, repo, checkpoint, local_head) reupload_nodes = verify_nodes.reject { |x| knife.verify_node_upload(File.split(x)[-1], verify_checkpoint) } reupload_nodes.each do |x| node_file = File.join(RunningSushi::Config.master_path, RunningSushi::Config.reponame, node_dir) + "/#{x}.json" - if File.file?(node_file) - # Only re-upload if node has not been deleted from repo - node_proxy = ChangeProxy.new(x) - added_nodes.push(node_proxy) - end + next unless File.file?(node_file) + + # Only re-upload if node has not been deleted from repo + node_proxy = ChangeProxy.new(x) + added_nodes.push(node_proxy) end end @@ -226,12 +224,12 @@ def chef_upload(knife, repo, checkpoint, local_head) if deleted_roles_local deleted_roles_local.each do |x| rolefile = File.join(RunningSushi::Config.master_path, RunningSushi::Config.reponame, RunningSushi::Config.role_path) + "/#{x.name}.json" - if File.file?(rolefile) - role_proxy = ChangeProxy.new(x.name) - added_roles.push(role_proxy) - deleted_roles_local.reject! do |y| - x.name == y.name - end + next unless File.file?(rolefile) + + role_proxy = ChangeProxy.new(x.name) + added_roles.push(role_proxy) + deleted_roles_local.reject! do |y| + x.name == y.name end end end @@ -285,20 +283,20 @@ def upload_changed(repo, checkpoint) node_dir, client_dir, environment_dir, role_local_dir = get_pod_config knife = RunningSushi::Knife.new( - logger: RunningSushi::Log, - config: RunningSushi::Config.knife_config, - bin: RunningSushi::Config.knife_bin, - master_path: RunningSushi::Config.master_path, - base_dir: base_dir, - client_dir: File.join(base_dir, client_dir), - cookbook_dirs: RunningSushi::Config.cookbook_paths.map do |x| - File.join(base_dir, x) - end, - databag_dir: File.join(base_dir, RunningSushi::Config.databag_path), - environment_dir: File.join(base_dir, environment_dir), - node_dir: File.join(base_dir, node_dir), - role_dir: File.join(base_dir, RunningSushi::Config.role_path), - role_local_dir: File.join(base_dir, role_local_dir), + logger: RunningSushi::Log, + config: RunningSushi::Config.knife_config, + bin: RunningSushi::Config.knife_bin, + master_path: RunningSushi::Config.master_path, + base_dir: base_dir, + client_dir: File.join(base_dir, client_dir), + cookbook_dirs: RunningSushi::Config.cookbook_paths.map do |x| + File.join(base_dir, x) + end, + databag_dir: File.join(base_dir, RunningSushi::Config.databag_path), + environment_dir: File.join(base_dir, environment_dir), + node_dir: File.join(base_dir, node_dir), + role_dir: File.join(base_dir, RunningSushi::Config.role_path), + role_local_dir: File.join(base_dir, role_local_dir) ) chef_upload(knife, repo, checkpoint, local_head) @@ -315,17 +313,17 @@ def setup_config end opts.on('-v', '--verbosity', 'Verbosity level. Twice for debug.') do # If -vv is supplied this block is executed twice - if options[:verbosity] - options[:verbosity] = ::Logger::DEBUG - else - options[:verbosity] = ::Logger::INFO - end + options[:verbosity] = if options[:verbosity] + ::Logger::DEBUG + else + ::Logger::INFO + end end opts.on('-T', '--timestamp', 'Timestamp output') do |s| options[:timestamp] = s end opts.on('-c', '--config-file FILE', 'config file') do |s| - unless File.exists?(File.expand_path(s)) + unless File.exist?(File.expand_path(s)) RunningSushi::Log.error("Config file #{s} not found.") exit(2) end @@ -338,7 +336,7 @@ def setup_config options[:pidfile] = s end end.parse! - if File.exists?(File.expand_path(options[:config_file])) + if File.exist?(File.expand_path(options[:config_file])) RunningSushi::Config.from_file(options[:config_file]) end RunningSushi::Config.merge!(options) @@ -405,8 +403,8 @@ if RunningSushi::Config.dry_run && !repo.exists? end checkpoint = read_checkpoint -node_checkpoint, uploaded_nodes = read_node_checkpoint -if repo.exists? && repo.head_rev == checkpoint && uploaded_nodes.size == 0 +_node_checkpoint, uploaded_nodes = read_node_checkpoint +if repo.exists? && repo.head_rev == checkpoint && uploaded_nodes.empty? RunningSushi::Log.warn('Repo has not changed and no node uploads to check, nothing to do...') $success = true $status_msg = "Success at #{checkpoint}" diff --git a/lib/running_sushi/hooks.rb b/lib/running_sushi/hooks.rb index 11c4b46..aac4080 100644 --- a/lib/running_sushi/hooks.rb +++ b/lib/running_sushi/hooks.rb @@ -44,7 +44,7 @@ def self.atexit(_dryrun, _success, _msg) end def self.get(file) - class_eval(File.read(file), __FILE__, __LINE__) if File.exists?(file) + class_eval(File.read(file), __FILE__, __LINE__) if File.exist?(file) end end end diff --git a/lib/running_sushi/knife.rb b/lib/running_sushi/knife.rb index ce7be8a..33729a3 100644 --- a/lib/running_sushi/knife.rb +++ b/lib/running_sushi/knife.rb @@ -15,6 +15,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# rubocop:disable Style/RedundantReturn require 'json' require 'ffi_yajl' @@ -32,7 +33,6 @@ require 'chef/cookbook/cookbook_version_loader' require 'chef/cookbook_uploader' - module RunningSushi # Knife does not have a usable API for using it as a lib # This could be possibly refactored to touch its internals @@ -57,11 +57,9 @@ def initialize(opts = {}) end def http_api - begin - Chef::ServerAPI.new(Chef::Config[:chef_server_url]) - rescue - Chef::REST.new(Chef::Config[:chef_server_url]) - end + Chef::ServerAPI.new(Chef::Config[:chef_server_url]) + rescue + Chef::REST.new(Chef::Config[:chef_server_url]) end def environment_upload(environments) @@ -74,11 +72,11 @@ def environment_delete(environments) end def update_permissions(node) - return unless Chef::Node.list.include?(node) + return unless Chef.Node.list.include?(node) @logger.info "Running ACL Update for node: #{node}" begin - ace = http_api::get_rest("nodes/#{node}/_acl") + ace = http_api.get_rest("nodes/#{node}/_acl") rescue Net::HTTPServerException => e @logger.info 'ACL probably not supported, might be chef 11' return @@ -90,7 +88,7 @@ def update_permissions(node) ace[perm]['actors'] << node begin - http_api::put_rest("nodes/#{node}/_acl/#{perm}", perm => ace[perm]) + http_api.put_rest("nodes/#{node}/_acl/#{perm}", perm => ace[perm]) rescue Net::HTTPServerException => e @logger.warn "Failed to set permission : #{perm} on node #{node}" end @@ -98,7 +96,6 @@ def update_permissions(node) end end - def client_upload(clients) files = clients.map { |x| File.join(@client_dir, "#{x.full_name}.json") } files.each do |f| @@ -106,7 +103,6 @@ def client_upload(clients) r = FFI_Yajl::Parser.parse(IO.read(f)) client_name = r['name'] # Try updating client - # Delete client if it does exists begin chef_client = Chef::ApiClientV1.new() @@ -128,7 +124,6 @@ def client_upload(clients) # Update permissions (Chef 12 thing) update_permissions(r['name']) @logger.info "Updated/Created #{client_name}" - rescue Net::HTTPServerException => e raise e unless e.response.code == '404' @logger.warn "Should not be here! #{client_name}" @@ -141,7 +136,7 @@ def client_delete(clients) end def node_upload(nodes, checkpoint) - upload_standard('nodes', @node_dir, nodes, Chef::Node, checkpoint=checkpoint) + upload_standard('nodes', @node_dir, nodes, Chef::Node, checkpoint) end def node_delete(nodes) @@ -164,42 +159,39 @@ def role_local_delete(roles_local) delete_standard('roles_local', roles_local, Chef::Role) end - def upload_standard(component_type, path, components, klass, checkpoint=nil) + def upload_standard(component_type, path, components, klass, checkpoint = nil) # Handle upload using Chef objects - if components.any? + return unless components.any? - @logger.info "=== Uploading #{component_type} ===" - # Instatiate object using knife factory - loader = Chef::Knife::Core::ObjectLoader.new(klass, @logger) + @logger.info "=== Uploading #{component_type} ===" + # Instatiate object using knife factory + loader = Chef::Knife::Core::ObjectLoader.new(klass, @logger) - files = components.map { |x| File.join(path, "#{x.full_name}.json") } - files.each do |f| - @logger.info "Upload from #{f}" - updated = loader.object_from_file(f) + files = components.map { |x| File.join(path, "#{x.full_name}.json") } + files.each do |f| + @logger.info "Upload from #{f}" + updated = loader.object_from_file(f) - if checkpoint - updated.normal['running_sushi']['checkpoint'] = checkpoint - end - updated.save + updated.normal['running_sushi']['checkpoint'] = checkpoint if checkpoint + updated.save - update_permissions(updated.name()) if updated.is_a? Chef::Node - end + update_permissions(updated.name()) if updated.is_a? Chef::Node end end def delete_standard(component_type, components, klass) # Handle delete using Chef objects - if components.any? - @logger.info "=== Deleting #{component_type} ===" - components.each do |component| - @logger.info "Deleting #{component.name}" - begin - chef_component = klass.load(component.name) - chef_component.destroy - rescue Net::HTTPServerException => e - raise e unless e.response.code == '404' - @logger.info "#{component_type} #{component.name} not found. Cannot delete" - end + return unless components.any? + + @logger.info "=== Deleting #{component_type} ===" + components.each do |component| + @logger.info "Deleting #{component.name}" + begin + chef_component = klass.load(component.name) + chef_component.destroy + rescue Net::HTTPServerException => e + raise e unless e.response.code == '404' + @logger.info "#{component_type} #{component.name} not found. Cannot delete" end end end @@ -207,21 +199,21 @@ def delete_standard(component_type, components, klass) def databag_upload(databags) # Databag upload special handling # Load pattern for databags does not follow standard - if databags.any? - @logger.info '=== Uploading databags ===' - databags.group_by { |x| x.name }.each do |dbname, dbs| - create_databag_if_missing(dbname) - dbs.map do |x| - @logger.info "Upload #{dbname} #{x.item}" - db_item = File.join(@databag_dir, dbname, "#{x.item}.json") - loader = Chef::Knife::Core::ObjectLoader.new(Chef::DataBagItem, - @logger) - chef_db_item_json = loader.object_from_file(db_item) - chef_db_item = Chef::DataBagItem.new - chef_db_item.data_bag(dbname) - chef_db_item.raw_data = chef_db_item_json - chef_db_item.save - end + return unless databags.any? + + @logger.info '=== Uploading databags ===' + databags.group_by(&:name).each do |dbname, dbs| + create_databag_if_missing(dbname) + dbs.map do |x| + @logger.info "Upload #{dbname} #{x.item}" + db_item = File.join(@databag_dir, dbname, "#{x.item}.json") + loader = Chef::Knife::Core::ObjectLoader.new(Chef::DataBagItem, + @logger) + chef_db_item_json = loader.object_from_file(db_item) + chef_db_item = Chef::DataBagItem.new + chef_db_item.data_bag(dbname) + chef_db_item.raw_data = chef_db_item_json + chef_db_item.save end end end @@ -237,96 +229,88 @@ def create_databag_if_missing(databag) end def databag_delete(databags) - if databags.any? - @logger.info '=== Deleting databag items ===' - databags.group_by { |x| x.name }.each do |dbname, dbs| - dbs.map do |x| - @logger.info "Delete #{dbname} #{x.item}" - begin - chef_db_item = Chef::DataBagItem.load(dbname, x.item) - chef_db_item.destroy(dbname, x.item) - rescue Net::HTTPServerException => e - raise e unless e.response.code == '404' - @logger.info "#{x.item} not found. Cannot delete" - end + return unless databags.any? + + @logger.info '=== Deleting databag items ===' + databags.group_by(&:name).each do |dbname, dbs| + dbs.map do |x| + @logger.info "Delete #{dbname} #{x.item}" + begin + chef_db_item = Chef::DataBagItem.load(dbname, x.item) + chef_db_item.destroy(dbname, x.item) + rescue Net::HTTPServerException => e + raise e unless e.response.code == '404' + @logger.info "#{x.item} not found. Cannot delete" end - delete_databag_if_empty(dbname) end + delete_databag_if_empty(dbname) end end def delete_databag_if_empty(databag) - begin - if Chef::DataBag.load(databag).any? - return - end - @logger.info "Deleting empty databag #{databag}" - chef_databag = Chef::DataBag.new - chef_databag.name(databag) - chef_databag.destroy - rescue Net::HTTPServerException => e - raise e unless e.response.code == '404' - @logger.info "#{databag} not found. Cannot delete" - end + return if Chef::DataBag.load(databag).any? + + @logger.info "Deleting empty databag #{databag}" + chef_databag = Chef::DataBag.new + chef_databag.name(databag) + chef_databag.destroy + rescue Net::HTTPServerException => e + raise e unless e.response.code == '404' + @logger.info "#{databag} not found. Cannot delete" end def cookbook_upload(cookbooks) # Upload cookbooks using Chef cookbook uploader - if cookbooks.any? - @logger.info '=== Uploading cookbooks ===' - cookbooks.each do |cb| - @logger.info " Uploading #{cb}" - - # Load cookbook - full_cb_path = File.join(@base_dir, cb.cookbook_dir, cb.name) - cb_version_loader = \ - Chef::Cookbook::CookbookVersionLoader.new(full_cb_path) - cb_version_loader.load_cookbooks - - # Handle versioned tagged cookbook by extracting name - # from cookbook dir - # Currently (Chef 11) Knife uses dir name as cookbook name - cb_name, _ = cookbook_info(cb) - cb_version_loader.instance_variable_set(:@cookbook_name, cb_name) - cb_version = cb_version_loader.cookbook_version - chef_cb_uploader = Chef::CookbookUploader.new(cb_version, {}) - chef_cb_uploader.upload_cookbooks - - end + return unless cookbooks.any? + + @logger.info '=== Uploading cookbooks ===' + cookbooks.each do |cb| + @logger.info " Uploading #{cb}" + + # Load cookbook + full_cb_path = File.join(@base_dir, cb.cookbook_dir, cb.name) + cb_version_loader = \ + Chef::Cookbook::CookbookVersionLoader.new(full_cb_path) + cb_version_loader.load_cookbooks + + # Handle versioned tagged cookbook by extracting name + # from cookbook dir + # Currently (Chef 11) Knife uses dir name as cookbook name + cb_name, = cookbook_info(cb) + cb_version_loader.instance_variable_set(:@cookbook_name, cb_name) + cb_version = cb_version_loader.cookbook_version + chef_cb_uploader = Chef::CookbookUploader.new(cb_version, {}) + chef_cb_uploader.upload_cookbooks end end def cookbook_delete(cookbooks) # Delete cookbooks using knife - if cookbooks.any? - @logger.info '=== Deleting cookbooks ===' + return unless cookbooks.any? - cookbooks.each do |cb| - @logger.info " Deleting #{cb}" - cb_name, cb_version = cookbook_info(cb) - chef_cb_deleter = Chef::Knife::CookbookDelete.new - Chef::Knife::CookbookDelete.load_deps - chef_cb_deleter.config[:purge] = true - chef_cb_deleter.cookbook_name = cb_name + @logger.info '=== Deleting cookbooks ===' - begin - - if cb_version - @logger.info " Deleting #{cb_version}" - chef_cb_deleter.delete_version_without_confirmation(cb_version) - else - @logger.info ' Deleting all' - chef_cb_deleter.delete_all_without_confirmation - end + cookbooks.each do |cb| + @logger.info " Deleting #{cb}" + cb_name, cb_version = cookbook_info(cb) + chef_cb_deleter = Chef::Knife::CookbookDelete.new + Chef::Knife::CookbookDelete.load_deps + chef_cb_deleter.config[:purge] = true + chef_cb_deleter.cookbook_name = cb_name - rescue Net::HTTPServerException => e - raise e unless e.response.code == '404' - @logger.info "#{cb_name} #{cb_version} not found. Cannot delete" + begin + if cb_version + @logger.info " Deleting #{cb_version}" + chef_cb_deleter.delete_version_without_confirmation(cb_version) + else + @logger.info ' Deleting all' + chef_cb_deleter.delete_all_without_confirmation end + rescue Net::HTTPServerException => e + raise e unless e.response.code == '404' + @logger.info "#{cb_name} #{cb_version} not found. Cannot delete" end - end - end def cookbook_info(cookbook) @@ -353,10 +337,10 @@ def verify_node_upload(node, checkpoint) if chef_node.normal['running_sushi']['checkpoint'] != checkpoint @logger.info " Upload verify of #{node} failed. Reuploading" return false - else - return true end - rescue Exception => e + + return true + rescue StandardError @logger.info " Upload verify of #{node} failed. Reuploading" return false end diff --git a/lib/running_sushi/logging.rb b/lib/running_sushi/logging.rb index 4526e9c..60a5565 100644 --- a/lib/running_sushi/logging.rb +++ b/lib/running_sushi/logging.rb @@ -45,17 +45,17 @@ def self.logit(level, msg) end def self.debug(msg) - if @@level == Logger::DEBUG - msg.prepend('DEBUG: ') - logit(Syslog::LOG_DEBUG, msg) - end + return unless @@level == Logger::DEBUG + + msg.prepend('DEBUG: ') + logit(Syslog::LOG_DEBUG, msg) end def self.info(msg) - if @@level <= Logger::INFO - msg.prepend('INFO: ') - logit(Syslog::LOG_INFO, msg) - end + return unless @@level <= Logger::INFO + + msg.prepend('INFO: ') + logit(Syslog::LOG_INFO, msg) end def self.warn(msg) diff --git a/running_sushi.gemspec b/running_sushi.gemspec index f09eeda..79a6655 100644 --- a/running_sushi.gemspec +++ b/running_sushi.gemspec @@ -6,14 +6,13 @@ Gem::Specification.new do |s| s.description = 'Utility for keeping Chef servers in sync with a repo' s.authors = ['Esben S. Nielsen'] s.extra_rdoc_files = ['README.md', 'LICENSE'] - s.files = %w{README.md LICENSE} + Dir.glob("lib/running_sushi/*.rb") + - Dir.glob("bin/*") + s.files = %w(README.md LICENSE) + Dir.glob('lib/running_sushi/*.rb') + Dir.glob('bin/*') s.executables = 'running-sushi' s.license = 'Apache' - %w{ + %w( mixlib-config chef_diff - }.each do |dep| + ).each do |dep| s.add_dependency dep end end