From 04bbbdff2219a912ae8aa1acab464fcf0ffd6fb4 Mon Sep 17 00:00:00 2001 From: haseeb-ahmad Date: Fri, 8 Dec 2023 20:09:15 +0500 Subject: [PATCH] CDB-8052 CDB-8050 Upgraded to ruby 3.1.2 (#305) * CPD-8050: Update to ruby 3.1.2 * Fixed s3 client keyword argument error * CPD-8050: volume_id fix for instance hash * CPD-8052: moonhot status output fix * CPD-8050: rubocop fixes * CPD-8050: Fixed rubocop Naming/MethodParameterName. --------- Co-authored-by: rutuja810 Co-authored-by: Kaushik Sirineni --- .rubocop.yml | 6 +- .ruby-version | 2 +- .travis.yml | 23 ----- Gemfile | 6 +- Rakefile | 4 +- bin/moonshot | 5 +- lib/moonshot.rb | 6 ++ lib/moonshot/account_context.rb | 4 +- lib/moonshot/always_use_default_source.rb | 8 +- lib/moonshot/artifact_repository/s3_bucket.rb | 2 +- .../s3_bucket_via_github_releases.rb | 14 +-- lib/moonshot/ask_user_source.rb | 18 ++-- .../build_mechanism/github_release.rb | 11 ++- lib/moonshot/build_mechanism/script.rb | 15 ++-- lib/moonshot/build_mechanism/travis_deploy.rb | 10 +-- lib/moonshot/build_mechanism/version_proxy.rb | 8 +- lib/moonshot/change_set.rb | 28 +++--- lib/moonshot/command.rb | 6 +- lib/moonshot/command_line.rb | 21 +++-- lib/moonshot/command_line_dispatcher.rb | 12 ++- lib/moonshot/commands/console.rb | 2 + lib/moonshot/commands/delete.rb | 4 +- lib/moonshot/commands/deploy.rb | 2 + lib/moonshot/commands/doctor.rb | 2 + lib/moonshot/commands/generate_template.rb | 2 + lib/moonshot/commands/interactive_command.rb | 2 + lib/moonshot/commands/list.rb | 2 + lib/moonshot/commands/new.rb | 53 ++++++------ lib/moonshot/commands/parameter_arguments.rb | 9 +- lib/moonshot/commands/parent_stack_option.rb | 2 + lib/moonshot/commands/push.rb | 2 + .../commands/show_all_events_option.rb | 2 + lib/moonshot/commands/status.rb | 2 + lib/moonshot/commands/tag_arguments.rb | 6 +- lib/moonshot/commands/update.rb | 6 +- lib/moonshot/commands/version.rb | 2 + lib/moonshot/config.rb | 1 + lib/moonshot/controller.rb | 28 +++--- lib/moonshot/controller_config.rb | 34 ++------ lib/moonshot/creds_helper.rb | 2 + .../deployment_mechanism/code_deploy.rb | 85 ++++++++++--------- lib/moonshot/doctor_helper.rb | 29 +++---- lib/moonshot/dynamic_template.rb | 3 + lib/moonshot/interactive_logger_proxy.rb | 8 +- lib/moonshot/parameter_collection.rb | 3 + lib/moonshot/parent_stack_parameter_loader.rb | 10 ++- lib/moonshot/resources.rb | 2 + lib/moonshot/resources_helper.rb | 6 +- lib/moonshot/shell.rb | 18 ++-- lib/moonshot/ssh_command.rb | 2 + lib/moonshot/ssh_command_builder.rb | 4 +- lib/moonshot/ssh_config.rb | 6 +- lib/moonshot/ssh_fork_executor.rb | 2 + lib/moonshot/ssh_target_selector.rb | 6 +- lib/moonshot/stack.rb | 84 +++++++++--------- lib/moonshot/stack_asg_printer.rb | 13 +-- lib/moonshot/stack_config.rb | 5 +- lib/moonshot/stack_events_poller.rb | 4 +- lib/moonshot/stack_list_printer.rb | 2 + lib/moonshot/stack_lister.rb | 10 ++- lib/moonshot/stack_output_printer.rb | 2 + lib/moonshot/stack_parameter.rb | 14 ++- lib/moonshot/stack_parameter_printer.rb | 4 +- lib/moonshot/stack_template.rb | 2 + lib/moonshot/task.rb | 3 + lib/moonshot/tools/asg_rollout.rb | 30 ++++--- lib/moonshot/tools/asg_rollout/asg.rb | 38 ++++----- .../tools/asg_rollout/asg_instance.rb | 2 + .../asg_rollout/hook_exec_environment.rb | 2 + .../tools/asg_rollout/instance_health.rb | 2 + lib/moonshot/tools/asg_rollout_config.rb | 2 + lib/moonshot/unicode_table.rb | 8 +- lib/moonshot/yaml_stack_template.rb | 2 + lib/plugins/backup.rb | 71 ++++++++-------- lib/plugins/code_deploy_setup.rb | 6 +- lib/plugins/dynamic_template.rb | 10 ++- lib/plugins/encrypted_parameters.rb | 6 +- lib/plugins/encrypted_parameters/kms_key.rb | 17 ++-- .../parameter_encrypter.rb | 2 + lib/plugins/rotate_asg_instances/asg.rb | 37 ++++---- lib/plugins/rotate_asg_instances/ssh.rb | 3 + moonshot.gemspec | 6 +- sample/Gemfile | 2 + spec/moonshot/commands/build_spec.rb | 6 +- spec/moonshot/shell_spec.rb | 2 +- spec/moonshot/stack_spec.rb | 2 +- 86 files changed, 532 insertions(+), 425 deletions(-) delete mode 100644 .travis.yml diff --git a/.rubocop.yml b/.rubocop.yml index 3cf76d77..e130f0d8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,6 +1,6 @@ --- AllCops: - TargetRubyVersion: 2.2 + TargetRubyVersion: 3.1.2 Exclude: - '.gemspec' - 'vendor/**/*' @@ -20,3 +20,7 @@ Metrics/ClassLength: Max: 130 Style/Documentation: Enabled: false +Naming/HeredocDelimiterNaming: + Enabled: false +Style/HashSyntax: + Enabled: false diff --git a/.ruby-version b/.ruby-version index 743af5e1..ef538c28 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.6.8 +3.1.2 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 28a79308..00000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- -language: ruby - -cache: bundler -# This will enable the container-based infrastructure for -# travis tests. It should result in faster test vm load times. -# @see http://docs.travis-ci.com/user/workers/container-based-infrastructure/ -sudo: false - -addons: - apt: - sources: - - kalakris-cmake - packages: - - cmake - -before_install: - - gem install rubygems-update -v '<3' --no-document && update_rubygems - - gem update bundler - -rvm: - - 2.6 - - 2.7 diff --git a/Gemfile b/Gemfile index b9e7bf42..7fb1127a 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + source 'https://rubygems.org' gemspec @@ -6,6 +8,8 @@ gem 'rake', require: false group :test do gem 'codeclimate-test-reporter' - gem 'rubocop', '~> 0.38.0' gem 'pry' + gem 'rubocop' end + +gem 'webrick', '~> 1.8' diff --git a/Rakefile b/Rakefile index 79c9da1e..e5544560 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'bundler/setup' require 'rspec/core/rake_task' require 'rubocop/rake_task' @@ -10,4 +12,4 @@ end RSpec::Core::RakeTask.new(:spec) -task default: [:spec, :rubocop] +task default: %i[spec rubocop] diff --git a/bin/moonshot b/bin/moonshot index eb69ea8a..2badc150 100755 --- a/bin/moonshot +++ b/bin/moonshot @@ -1,11 +1,14 @@ #!/usr/bin/env ruby +# frozen_string_literal: true + require 'moonshot' # This is the main entry point for the `moonshot` command-line tool. begin Moonshot::CommandLine.new.run! -rescue => e +rescue StandardError => e warn "#{e} (at #{e.backtrace.first})" raise e if ENV['MOONSHOT_BACKTRACE'] + exit 1 end diff --git a/lib/moonshot.rb b/lib/moonshot.rb index 5b43024d..78cbd9e8 100644 --- a/lib/moonshot.rb +++ b/lib/moonshot.rb @@ -1,5 +1,8 @@ +# frozen_string_literal: true + require 'English' require 'aws-sdk' + require 'logger' require 'thor' require 'interactive-logger' @@ -16,10 +19,13 @@ def self.config module ArtifactRepository end + module BuildMechanism end + module DeploymentMechanism end + module Plugins end end diff --git a/lib/moonshot/account_context.rb b/lib/moonshot/account_context.rb index fa3f5171..f22cc24f 100644 --- a/lib/moonshot/account_context.rb +++ b/lib/moonshot/account_context.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + module Moonshot module AccountContext def self.get - @account ||= determine_account_name + @get ||= determine_account_name end def self.set(account_name) diff --git a/lib/moonshot/always_use_default_source.rb b/lib/moonshot/always_use_default_source.rb index de4bf16a..18b56b20 100644 --- a/lib/moonshot/always_use_default_source.rb +++ b/lib/moonshot/always_use_default_source.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot # The AlwaysUseDefaultSource will always use the previous value in # the stack, or use the default value during stack creation. This is @@ -5,12 +7,12 @@ module Moonshot # want to prompt the user for an override. Of course, overrides from # answer files or command-line arguments will always apply. class AlwaysUseDefaultSource - def get(sp) + def get(param) # Don't do anything, the default will apply on create, and the # previous value will be used on update. - return if sp.default? + return if param.default? - raise "Parameter #{sp.name} does not have a default, cannot use AlwaysUseDefaultSource!" + raise "Parameter #{param.name} does not have a default, cannot use AlwaysUseDefaultSource!" end end end diff --git a/lib/moonshot/artifact_repository/s3_bucket.rb b/lib/moonshot/artifact_repository/s3_bucket.rb index 8a849fd2..e2837988 100644 --- a/lib/moonshot/artifact_repository/s3_bucket.rb +++ b/lib/moonshot/artifact_repository/s3_bucket.rb @@ -47,7 +47,7 @@ def filename_for_version(version_name) def upload_to_s3(file, key) s3_client.put_object( acl: 'bucket-owner-full-control', - key: key, + key:, body: File.open(file), bucket: @bucket_name, storage_class: 'STANDARD_IA' diff --git a/lib/moonshot/artifact_repository/s3_bucket_via_github_releases.rb b/lib/moonshot/artifact_repository/s3_bucket_via_github_releases.rb index d15984d5..caac00c8 100644 --- a/lib/moonshot/artifact_repository/s3_bucket_via_github_releases.rb +++ b/lib/moonshot/artifact_repository/s3_bucket_via_github_releases.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'moonshot/artifact_repository/s3_bucket' require 'moonshot/shell' require 'digest' @@ -9,7 +11,7 @@ module Moonshot::ArtifactRepository # S3 Bucket repository backed by GitHub releases. # If a SemVer package isn't found in S3, it is copied from GitHub releases. - class S3BucketViaGithubReleases < S3Bucket # rubocop:disable ClassLength + class S3BucketViaGithubReleases < S3Bucket # rubocop:disable Metrics/ClassLength include Moonshot::BuildMechanism include Moonshot::Shell @@ -36,9 +38,7 @@ def store_hook(build_mechanism, version) # artifact repositories a hook before deploy. def filename_for_version(version) s3_name = super - if !@output_file && release?(version) && !in_s3?(s3_name) - github_to_s3(version, s3_name) - end + github_to_s3(version, s3_name) if !@output_file && release?(version) && !in_s3?(s3_name) s3_name end @@ -51,7 +51,7 @@ def release?(version) end def in_s3?(key) - s3_client.head_object(key: key, bucket: bucket_name) + s3_client.head_object(key:, bucket: bucket_name) rescue ::Aws::S3::Errors::NotFound false end @@ -62,7 +62,7 @@ def attach_release_asset(version, file) # If there is a checksum file, attach it as well. We only support MD5 # since that's what S3 uses. - checksum_file = File.basename(file, '.tar.gz') + '.md5' + checksum_file = "#{File.basename(file, '.tar.gz')}.md5" cmd += " --attach=#{checksum_file}" if File.exist?(checksum_file) sh_step(cmd) @@ -218,7 +218,7 @@ def backup_failed_s3_file(s3_name, attempt) def doctor_check_hub_release_download sh_out('hub release download --help') - rescue + rescue StandardError critical '`hub release download` command missing, upgrade hub.' \ ' See https://github.com/github/hub/pull/1103' else diff --git a/lib/moonshot/ask_user_source.rb b/lib/moonshot/ask_user_source.rb index e01d90ba..c12c0381 100644 --- a/lib/moonshot/ask_user_source.rb +++ b/lib/moonshot/ask_user_source.rb @@ -1,24 +1,26 @@ +# frozen_string_literal: true + require 'colorize' module Moonshot class AskUserSource - def get(sp) + def get(param) return unless Moonshot.config.interactive - @sp = sp + @param = param prompt loop do input = gets.chomp - if String(input).empty? && @sp.default? + if String(input).empty? && @param.default? # We will use the default value, print it here so the output is clear. puts 'Using default value.' return elsif String(input).empty? - puts "Cannot proceed without value for #{@sp.name}!" + puts "Cannot proceed without value for #{@param.name}!" else - @sp.set(String(input)) + @param.set(String(input)) return end @@ -29,9 +31,9 @@ def get(sp) private def prompt - print "(#{@sp.name})".light_black - print " #{@sp.description}" unless @sp.description.empty? - print " [#{@sp.default}]".light_black if @sp.default? + print "(#{@param.name})".light_black + print " #{@param.description}" unless @param.description.empty? + print " [#{@param.default}]".light_black if @param.default? print ': ' end end diff --git a/lib/moonshot/build_mechanism/github_release.rb b/lib/moonshot/build_mechanism/github_release.rb index 5fe56d9d..3bb27aac 100644 --- a/lib/moonshot/build_mechanism/github_release.rb +++ b/lib/moonshot/build_mechanism/github_release.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'forwardable' require 'moonshot/shell' require 'open3' @@ -40,9 +42,9 @@ def doctor_hook @build_mechanism.doctor_hook end - def resources=(r) + def resources=(res) super - @build_mechanism.resources = r + @build_mechanism.resources = res end def pre_build_hook(version) @@ -135,6 +137,7 @@ def git_push_tag(remote, tag) def hub_create_release(semver, commitish, changelog_entry) return if hub_release_exists(semver) + message = "#{semver}\n\n#{changelog_entry}" cmd = "hub release create #{semver} --commitish=#{commitish}" cmd << ' --prerelease' if semver.pre || semver.build @@ -220,7 +223,7 @@ def releases_url def doctor_check_upstream sh_out('git remote | grep ^upstream$') - rescue => e + rescue StandardError => e critical "git remote `upstream` not found.\n#{e.message}" else success 'git remote `upstream` exists.' @@ -228,7 +231,7 @@ def doctor_check_upstream def doctor_check_hub_auth sh_out('hub ci-status master') - rescue => e + rescue StandardError => e critical "`hub` failed, install hub and authorize it.\n#{e.message}" else success '`hub` installed and authorized.' diff --git a/lib/moonshot/build_mechanism/script.rb b/lib/moonshot/build_mechanism/script.rb index 75eef3a0..d51b9fd2 100644 --- a/lib/moonshot/build_mechanism/script.rb +++ b/lib/moonshot/build_mechanism/script.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require 'open3' -include Open3 # Compile a release artifact using a shell script. # @@ -18,6 +19,8 @@ class Moonshot::BuildMechanism::Script include Moonshot::ResourcesHelper include Moonshot::DoctorHelper + include Open3 + attr_reader :output_file def initialize(script, output_file: 'output.tar.gz') @@ -35,12 +38,12 @@ def build_hook(version) 'OUTPUT_FILE' => @output_file } ilog.start_threaded "Running Script: #{@script}" do |s| - run_script(s, env: env) + run_script(s, env:) end end def post_build_hook(_version) - unless File.exist?(@output_file) # rubocop:disable GuardClause + unless File.exist?(@output_file) # rubocop:disable Style/GuardClause raise 'Build command did not produce output file!' end end @@ -61,10 +64,8 @@ def run_script(step, env: {}) end result = wait.value - if result.exitstatus == 0 - step.success "Build script #{@script} exited successfully!" - end - unless result.exitstatus == 0 + step.success "Build script #{@script} exited successfully!" if result.exitstatus.zero? + unless result.exitstatus.zero? ilog.error "Build script failed with exit status #{result.exitstatus}!" ilog.error output.join("\n") step.failure "Build script #{@script} failed with exit status #{result.exitstatus}!" diff --git a/lib/moonshot/build_mechanism/travis_deploy.rb b/lib/moonshot/build_mechanism/travis_deploy.rb index d88ac9d7..abd69384 100644 --- a/lib/moonshot/build_mechanism/travis_deploy.rb +++ b/lib/moonshot/build_mechanism/travis_deploy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'moonshot/shell' require 'travis' require 'travis/pro' @@ -25,8 +27,7 @@ def initialize(slug, pro: false, timeout: 900) @cli_args = "-r #{@slug} #{@endpoint}" end - def pre_build_hook(_) - end + def pre_build_hook(_); end def build_hook(version) job_number = find_build_and_job(version) @@ -34,8 +35,7 @@ def build_hook(version) check_build(version) end - def post_build_hook(_) - end + def post_build_hook(_); end private @@ -120,7 +120,7 @@ def check_build(version) def doctor_check_travis_auth sh_out("bundle exec travis raw #{@endpoint} repos/#{@slug}") - rescue => e + rescue StandardError => e critical "`travis` not available or not authorized.\n#{e.message}" else success '`travis` installed and authorized.' diff --git a/lib/moonshot/build_mechanism/version_proxy.rb b/lib/moonshot/build_mechanism/version_proxy.rb index 273ddd6e..d529c8c8 100644 --- a/lib/moonshot/build_mechanism/version_proxy.rb +++ b/lib/moonshot/build_mechanism/version_proxy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'forwardable' require 'semantic' @@ -19,10 +21,10 @@ def doctor_hook @dev.doctor_hook end - def resources=(r) + def resources=(res) super - @release.resources = r - @dev.resources = r + @release.resources = res + @dev.resources = res end def pre_build_hook(version) diff --git a/lib/moonshot/change_set.rb b/lib/moonshot/change_set.rb index f61797a2..41ef9589 100644 --- a/lib/moonshot/change_set.rb +++ b/lib/moonshot/change_set.rb @@ -1,7 +1,8 @@ +# frozen_string_literal: true + module Moonshot class ChangeSet - attr_reader :name - attr_reader :stack_name + attr_reader :name, :stack_name def initialize(name, stack_name) @name = name @@ -11,9 +12,7 @@ def initialize(name, stack_name) end def confirm? - unless Moonshot.config.interactive - raise 'Cannot confirm ChangeSet when interactive mode is disabled!' - end + raise 'Cannot confirm ChangeSet when interactive mode is disabled!' unless Moonshot.config.interactive loop do print 'Apply changes? ' @@ -21,6 +20,7 @@ def confirm? return true if resp == 'yes' return false if resp == 'no' + puts "Please enter 'yes' or 'no'!" end end @@ -33,15 +33,16 @@ def invalid_reason @change_set.status_reason end - def display_changes + def display_changes # rubocop:disable Metrics/CyclomaticComplexity wait_for_change_set unless @change_set @change_set.changes.map(&:resource_change).each do |c| puts "* #{c.action} #{c.logical_resource_id} (#{c.resource_type})" - if c.replacement == 'True' + case c.replacement + when 'True' puts ' - Will be replaced' - elsif c.replacement == 'Conditional' + when 'Conditional' puts ' - May be replaced (Conditional)' end @@ -60,14 +61,16 @@ def execute wait_for_change_set unless @change_set @cf_client.execute_change_set( change_set_name: @name, - stack_name: @stack_name) + stack_name: @stack_name + ) end def delete wait_for_change_set unless @change_set @cf_client.delete_change_set( change_set_name: @name, - stack_name: @stack_name) + stack_name: @stack_name + ) rescue Aws::CloudFormation::Errors::InvalidChangeSetStatus sleep 1 retry @@ -85,9 +88,10 @@ def wait_for_change_set loop do resp = @cf_client.describe_change_set( change_set_name: @name, - stack_name: @stack_name) + stack_name: @stack_name + ) - if %w(CREATE_COMPLETE FAILED).include?(resp.status) + if %w[CREATE_COMPLETE FAILED].include?(resp.status) @change_set = resp return end diff --git a/lib/moonshot/command.rb b/lib/moonshot/command.rb index fe2ec2fa..3f0ebe51 100644 --- a/lib/moonshot/command.rb +++ b/lib/moonshot/command.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'optparse' module Moonshot @@ -8,7 +10,7 @@ module ClassMethods attr_accessor :usage, :description, :only_in_account end - def self.inherited(base) + def self.inherited(base) # rubocop:disable Lint/MissingSuper Moonshot::CommandLine.register(base) base.extend(ClassMethods) end @@ -44,7 +46,7 @@ def controller # Degrade to a more compatible logger if the terminal seems outdated, # or at the users request. if !$stdout.isatty || !@use_interactive_logger - log = Logger.new(STDOUT) + log = Logger.new($stdout) controller.config.interactive_logger = InteractiveLoggerProxy.new(log) end diff --git a/lib/moonshot/command_line.rb b/lib/moonshot/command_line.rb index 384161c2..29fd1e2a 100644 --- a/lib/moonshot/command_line.rb +++ b/lib/moonshot/command_line.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot # This class implements the command-line `moonshot` tool. class CommandLine @@ -10,7 +12,7 @@ def self.registered_commands @classes || [] end - def run! # rubocop:disable CyclomaticComplexity, MethodLength, PerceivedComplexity + def run! # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity # Commands defined as Moonshot::Commands require a properly # configured Moonshot.rb and supporting files. Without them, we only # support `--help` and `new`. @@ -24,7 +26,7 @@ def run! # rubocop:disable CyclomaticComplexity, MethodLength, PerceivedComplexi if Dir.pwd == '/' warn 'No Moonfile.rb found, are you in a project? Maybe you need to '\ - 'create one with `moonshot new `?' + 'create one with `moonshot new `?' raise 'No Moonfile found' end @@ -51,7 +53,7 @@ def run! # rubocop:disable CyclomaticComplexity, MethodLength, PerceivedComplexi # Determine what command is being run, which should be the first argument. command = ARGV.shift - if %w(--help -h help).include?(command) || command.nil? + if %w[--help -h help].include?(command) || command.nil? usage return end @@ -94,7 +96,7 @@ def usage max_len = fields.map(&:first).map(&:size).max fields.each do |f| - line = format(" %-#{max_len}s # %s", *f) + line = format(" %-#{max_len}s # %s", *f) # rubocop:disable Lint/FormatParameterMismatch warn line end end @@ -117,9 +119,9 @@ def load_commands def commandify(klass) word = klass.to_s.split('::').last - word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze) - word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze) - word.tr!('_'.freeze, '-'.freeze) + word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2') + word.gsub!(/([a-z\d])([A-Z])/, '\1_\2') + word.tr!('_', '-') word.downcase! word end @@ -127,10 +129,11 @@ def commandify(klass) def handle_early_commands # If this is a legacy (Thor) help command, re-write it as # OptionParser format. - if ARGV[0] == 'help' + case ARGV[0] + when 'help' ARGV.delete_at(0) ARGV.push('-h') - elsif ARGV[0] == 'new' + when 'new' app_name = ARGV[1] ::Moonshot::Commands::New.run!(app_name) return true diff --git a/lib/moonshot/command_line_dispatcher.rb b/lib/moonshot/command_line_dispatcher.rb index 5fdfa6bc..e80c638b 100644 --- a/lib/moonshot/command_line_dispatcher.rb +++ b/lib/moonshot/command_line_dispatcher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot class CommandLineDispatcher def initialize(command, klass, args) @@ -46,18 +48,14 @@ def build_parser(handler) # Each mechanism / plugin may manipulate the OptionParser object # associated with this command. - [:build_mechanism, :deployment_mechanism, :artifact_repository].each do |prov| + %i[build_mechanism deployment_mechanism artifact_repository].each do |prov| provider = Moonshot.config.send(prov) - if provider.respond_to?(hook_func_name(@command)) - parser = provider.send(hook_func_name(@command), parser) - end + parser = provider.send(hook_func_name(@command), parser) if provider.respond_to?(hook_func_name(@command)) end Moonshot.config.plugins.each do |plugin| - if plugin.respond_to?(hook_func_name(@command)) - parser = plugin.send(hook_func_name(@command), parser) - end + parser = plugin.send(hook_func_name(@command), parser) if plugin.respond_to?(hook_func_name(@command)) end parser diff --git a/lib/moonshot/commands/console.rb b/lib/moonshot/commands/console.rb index 07456534..ec2167f8 100644 --- a/lib/moonshot/commands/console.rb +++ b/lib/moonshot/commands/console.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'pry' module Moonshot diff --git a/lib/moonshot/commands/delete.rb b/lib/moonshot/commands/delete.rb index 1f86107e..5d594bd4 100644 --- a/lib/moonshot/commands/delete.rb +++ b/lib/moonshot/commands/delete.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands class Delete < Moonshot::Command @@ -8,7 +10,7 @@ class Delete < Moonshot::Command def parser parser = super - parser.on('--template-file=FILE', 'Override the path to the CloudFormation template.') do |v| # rubocop:disable LineLength + parser.on('--template-file=FILE', 'Override the path to the CloudFormation template.') do |v| Moonshot.config.template_file = v end end diff --git a/lib/moonshot/commands/deploy.rb b/lib/moonshot/commands/deploy.rb index 2ac16e12..e7cc0e1c 100644 --- a/lib/moonshot/commands/deploy.rb +++ b/lib/moonshot/commands/deploy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands class Deploy < Moonshot::Command diff --git a/lib/moonshot/commands/doctor.rb b/lib/moonshot/commands/doctor.rb index 01925294..eb56c644 100644 --- a/lib/moonshot/commands/doctor.rb +++ b/lib/moonshot/commands/doctor.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands class Doctor < Moonshot::Command diff --git a/lib/moonshot/commands/generate_template.rb b/lib/moonshot/commands/generate_template.rb index 2532394f..364e028f 100644 --- a/lib/moonshot/commands/generate_template.rb +++ b/lib/moonshot/commands/generate_template.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands class GenerateTemplate < Moonshot::Command diff --git a/lib/moonshot/commands/interactive_command.rb b/lib/moonshot/commands/interactive_command.rb index 7abb4ccb..2416405b 100644 --- a/lib/moonshot/commands/interactive_command.rb +++ b/lib/moonshot/commands/interactive_command.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands module InteractiveCommand diff --git a/lib/moonshot/commands/list.rb b/lib/moonshot/commands/list.rb index b28574a4..7d2bd464 100644 --- a/lib/moonshot/commands/list.rb +++ b/lib/moonshot/commands/list.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands class List < Moonshot::Command diff --git a/lib/moonshot/commands/new.rb b/lib/moonshot/commands/new.rb index cf9fbc4f..fee675ce 100644 --- a/lib/moonshot/commands/new.rb +++ b/lib/moonshot/commands/new.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands class New < Moonshot::Command @@ -25,6 +27,7 @@ def run!(application_name) def create_project_dir raise "Directory '#{@application_name}' already exists!" \ if Dir.exist?(project_path) + Dir.mkdir(project_path) end @@ -42,34 +45,34 @@ def fill_moonfile end def generate_moonfile - <<-EOF -Moonshot.config do |m| - m.app_name = '#{@application_name}' - m.artifact_repository = S3Bucket.new('') - m.build_mechanism = Script.new('bin/build.sh') - m.deployment_mechanism = CodeDeploy.new(asg: 'AutoScalingGroup') -end -EOF + <<~EOF + Moonshot.config do |m| + m.app_name = '#{@application_name}' + m.artifact_repository = S3Bucket.new('') + m.build_mechanism = Script.new('bin/build.sh') + m.deployment_mechanism = CodeDeploy.new(asg: 'AutoScalingGroup') + end + EOF end def print_success_message - warn <<-EOF -Your application is configured, the following changes have been made -to your project directory: - - * Created Moonfile.rb, where you can configure your project. - * Created moonshot/plugins, where you can place custom Ruby code - to add hooks to core Moonshot actions (create, update, delete, etc.) - * Created moonshot/cli_extensions, where you can place custom Ruby - code to add your own project-specific commands to Moonshot. - * Created moonshot/template.yml, where you can build your - CloudFormation template. - -You will also need to ensure your Amazon account is configured for -CodeDeploy by creating a role that allows deployments. - -See: http://moonshot.readthedocs.io/en/latest/mechanisms/deployment/ -EOF + warn <<~EOF + Your application is configured, the following changes have been made + to your project directory: + + * Created Moonfile.rb, where you can configure your project. + * Created moonshot/plugins, where you can place custom Ruby code + to add hooks to core Moonshot actions (create, update, delete, etc.) + * Created moonshot/cli_extensions, where you can place custom Ruby + code to add your own project-specific commands to Moonshot. + * Created moonshot/template.yml, where you can build your + CloudFormation template. + + You will also need to ensure your Amazon account is configured for + CodeDeploy by creating a role that allows deployments. + + See: http://moonshot.readthedocs.io/en/latest/mechanisms/deployment/ + EOF end end end diff --git a/lib/moonshot/commands/parameter_arguments.rb b/lib/moonshot/commands/parameter_arguments.rb index 1dec6a96..c377fc6f 100644 --- a/lib/moonshot/commands/parameter_arguments.rb +++ b/lib/moonshot/commands/parameter_arguments.rb @@ -1,4 +1,6 @@ -# rubocop:disable LineLength +# frozen_string_literal: true + +# rubocop:disable Layout/LineLength module Moonshot module Commands module ParameterArguments @@ -15,9 +17,7 @@ def parser parser.on('--parameter KEY=VALUE', '-PKEY=VALUE', 'Specify Stack Parameter on the command line') do |v| data = v.split('=', 2) - unless data.size == 2 - raise "Invalid parameter format '#{v}', expected KEY=VALUE (e.g. MyStackParameter=12)" - end + raise "Invalid parameter format '#{v}', expected KEY=VALUE (e.g. MyStackParameter=12)" unless data.size == 2 Moonshot.config.parameter_overrides[data[0]] = data[1] end @@ -25,3 +25,4 @@ def parser end end end +# rubocop:enable Layout/LineLength diff --git a/lib/moonshot/commands/parent_stack_option.rb b/lib/moonshot/commands/parent_stack_option.rb index 3fd32daf..b1ef7163 100644 --- a/lib/moonshot/commands/parent_stack_option.rb +++ b/lib/moonshot/commands/parent_stack_option.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands module ParentStackOption diff --git a/lib/moonshot/commands/push.rb b/lib/moonshot/commands/push.rb index 62ff5291..c6d009a6 100644 --- a/lib/moonshot/commands/push.rb +++ b/lib/moonshot/commands/push.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands class Push < Moonshot::Command diff --git a/lib/moonshot/commands/show_all_events_option.rb b/lib/moonshot/commands/show_all_events_option.rb index f8921526..fe879bbe 100644 --- a/lib/moonshot/commands/show_all_events_option.rb +++ b/lib/moonshot/commands/show_all_events_option.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands module ShowAllEventsOption diff --git a/lib/moonshot/commands/status.rb b/lib/moonshot/commands/status.rb index b35d8246..68caef32 100644 --- a/lib/moonshot/commands/status.rb +++ b/lib/moonshot/commands/status.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands class Status < Moonshot::Command diff --git a/lib/moonshot/commands/tag_arguments.rb b/lib/moonshot/commands/tag_arguments.rb index a09abe1a..8e8aef1f 100644 --- a/lib/moonshot/commands/tag_arguments.rb +++ b/lib/moonshot/commands/tag_arguments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands module TagArguments @@ -6,9 +8,7 @@ def parser parser.on('--tag KEY=VALUE', '-TKEY=VALUE', 'Specify Stack Tag on the command line') do |v| data = v.split('=', 2) - unless data.size == 2 - raise "Invalid tag format '#{v}', expected KEY=VALUE (e.g. MyStackTag=12)" - end + raise "Invalid tag format '#{v}', expected KEY=VALUE (e.g. MyStackTag=12)" unless data.size == 2 Moonshot.config.extra_tags << { key: data[0], value: data[1] } end diff --git a/lib/moonshot/commands/update.rb b/lib/moonshot/commands/update.rb index 9e7a99cb..5dba1639 100644 --- a/lib/moonshot/commands/update.rb +++ b/lib/moonshot/commands/update.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands class Update < Moonshot::Command @@ -12,7 +14,7 @@ class Update < Moonshot::Command def parser parser = super - parser.on('--dry-run', TrueClass, 'Show the changes that would be applied, but do not execute them') do |v| # rubocop:disable LineLength + parser.on('--dry-run', TrueClass, 'Show the changes that would be applied, but do not execute them') do |v| @dry_run = v end @@ -24,7 +26,7 @@ def parser @refresh_parameters = v end - parser.on('--template-file=FILE', 'Override the path to the CloudFormation template.') do |v| # rubocop:disable LineLength + parser.on('--template-file=FILE', 'Override the path to the CloudFormation template.') do |v| Moonshot.config.template_file = v end end diff --git a/lib/moonshot/commands/version.rb b/lib/moonshot/commands/version.rb index ed75b54a..2530a684 100644 --- a/lib/moonshot/commands/version.rb +++ b/lib/moonshot/commands/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Commands class Version < Moonshot::Command diff --git a/lib/moonshot/config.rb b/lib/moonshot/config.rb index e69de29b..8e9b8f90 100644 --- a/lib/moonshot/config.rb +++ b/lib/moonshot/config.rb @@ -0,0 +1 @@ +# frozen_string_literal: true diff --git a/lib/moonshot/controller.rb b/lib/moonshot/controller.rb index c42b04ad..cc81250e 100644 --- a/lib/moonshot/controller.rb +++ b/lib/moonshot/controller.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + module Moonshot # The Controller coordinates and performs all Moonshot actions. - class Controller # rubocop:disable ClassLength + class Controller # rubocop:disable Metrics/ClassLength attr_accessor :config def initialize(config) @@ -11,7 +13,7 @@ def list Moonshot::StackLister.new(@config.app_name).list end - def create # rubocop:disable AbcSize + def create # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity run_plugins(:setup_create) # Scan the template for all required parameters and configure # the ParameterCollection. @@ -35,7 +37,7 @@ def create # rubocop:disable AbcSize # Interview the user for missing parameters, using the # appropriate prompts. - @config.parameters.values.each do |sp| + @config.parameters.hash.each_value do |sp| next if sp.set? parameter_source = @config.parameter_sources.fetch(sp.name, @@ -51,12 +53,12 @@ def create # rubocop:disable AbcSize # Fail if any parameters are still missing without defaults. missing_parameters = @config.parameters.missing_for_create unless missing_parameters.empty? - raise "The following parameters were not provided: #{missing_parameters.map(&:name).join(', ')}" # rubocop:disable LineLength + raise "The following parameters were not provided: #{missing_parameters.map(&:name).join(', ')}" end run_hook(:deploy, :pre_create) stack_ok = stack.create - if stack_ok # rubocop:disable GuardClause + if stack_ok # rubocop:disable Style/GuardClause run_hook(:deploy, :post_create) run_plugins(:post_create) else @@ -64,7 +66,7 @@ def create # rubocop:disable AbcSize end end - def update(dry_run:, force:, refresh_parameters:) # rubocop:disable AbcSize + def update(dry_run:, force:, refresh_parameters:) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity run_plugins(:setup_update) # Scan the template for all required parameters and configure # the ParameterCollection. @@ -108,11 +110,11 @@ def update(dry_run:, force:, refresh_parameters:) # rubocop:disable AbcSize # Fail if any parameters are still missing without defaults. missing_parameters = @config.parameters.missing_for_update unless missing_parameters.empty? - raise "The following parameters were not provided: #{missing_parameters.map(&:name).join(', ')}" # rubocop:disable LineLength + raise "The following parameters were not provided: #{missing_parameters.map(&:name).join(', ')}" end run_hook(:deploy, :pre_update) - stack.update(dry_run: dry_run, force: force) + stack.update(dry_run:, force:) run_hook(:deploy, :post_update) run_plugins(:post_update) end @@ -159,7 +161,7 @@ def delete run_plugins(:pre_delete) run_hook(:deploy, :pre_delete) stack_ok = stack.delete - if stack_ok # rubocop:disable GuardClause + if stack_ok # rubocop:disable Style/GuardClause run_hook(:deploy, :post_delete) run_plugins(:post_delete) else @@ -182,7 +184,8 @@ def doctor def ssh run_plugins(:pre_ssh) @config.ssh_instance ||= SSHTargetSelector.new( - stack, asg_name: @config.ssh_auto_scaling_group_name).choose! + stack, asg_name: @config.ssh_auto_scaling_group_name + ).choose! cb = SSHCommandBuilder.new(@config.ssh_config, @config.ssh_instance) result = cb.build(@config.ssh_command) @@ -198,14 +201,14 @@ def stack def resources @resources ||= - Resources.new(stack: stack, ilog: @config.interactive_logger, controller: self) + Resources.new(stack:, ilog: @config.interactive_logger, controller: self) end def run_hook(type, name, *args) mech = get_mechanism(type) name = name.to_s << '_hook' - return unless mech && mech.respond_to?(name) + return unless mech.respond_to?(name) mech.resources = resources mech.send(name, *args) @@ -215,6 +218,7 @@ def run_plugins(type) results = {} @config.plugins.each do |plugin| next unless plugin.respond_to?(type) + results[plugin] = if type =~ /^setup_/ plugin.send(type) diff --git a/lib/moonshot/controller_config.rb b/lib/moonshot/controller_config.rb index 90077f2c..c6486dcc 100644 --- a/lib/moonshot/controller_config.rb +++ b/lib/moonshot/controller_config.rb @@ -1,34 +1,16 @@ +# frozen_string_literal: true + module Moonshot # Holds configuration for Moonshot::Controller class ControllerConfig attr_reader :account_alias - attr_accessor :additional_tag - attr_accessor :answer_file - attr_accessor :app_name - attr_accessor :artifact_repository - attr_accessor :build_mechanism - attr_accessor :changeset_wait_time - attr_accessor :deployment_mechanism - attr_accessor :dev_build_name_proc - attr_accessor :environment_name - attr_accessor :extra_tags - attr_accessor :interactive - attr_accessor :interactive_logger - attr_accessor :parameter_overrides - attr_accessor :parameters - attr_accessor :parent_stacks - attr_accessor :default_parameter_source - attr_accessor :parameter_sources - attr_accessor :plugins - attr_accessor :project_root - attr_accessor :show_all_stack_events - attr_accessor :ssh_auto_scaling_group_name - attr_accessor :ssh_command - attr_accessor :ssh_config - attr_accessor :ssh_instance - attr_accessor :template_file - attr_accessor :template_s3_bucket + attr_accessor :additional_tag, :answer_file, :app_name, :artifact_repository, :build_mechanism, + :changeset_wait_time, :deployment_mechanism, :dev_build_name_proc, :environment_name, + :extra_tags, :interactive, :interactive_logger, :parameter_overrides, :parameters, :parent_stacks, + :default_parameter_source, :parameter_sources, :plugins, :project_root, + :show_all_stack_events, :ssh_auto_scaling_group_name, :ssh_command, :ssh_config, + :ssh_instance, :template_file, :template_s3_bucket def initialize @default_parameter_source = AskUserSource.new diff --git a/lib/moonshot/creds_helper.rb b/lib/moonshot/creds_helper.rb index 9d892c94..3de5380a 100644 --- a/lib/moonshot/creds_helper.rb +++ b/lib/moonshot/creds_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot # Create convenience methods for various AWS client creation. module CredsHelper diff --git a/lib/moonshot/deployment_mechanism/code_deploy.rb b/lib/moonshot/deployment_mechanism/code_deploy.rb index 1af73e82..9b4ec888 100644 --- a/lib/moonshot/deployment_mechanism/code_deploy.rb +++ b/lib/moonshot/deployment_mechanism/code_deploy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'colorize' # This mechanism is used to deploy software to an auto-scaling group within @@ -8,12 +10,12 @@ # self.artifact_repository = S3Bucket.new('foobucket') # self.deployment_mechanism = CodeDeploy.new(asg: 'AutoScalingGroup') # end -class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength +class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable Metrics/ClassLength include Moonshot::ResourcesHelper include Moonshot::CredsHelper include Moonshot::DoctorHelper - DEFAULT_ROLE_NAME = 'CodeDeployRole'.freeze + DEFAULT_ROLE_NAME = 'CodeDeployRole' # @param asg [Array, String] # The logical name of the AutoScalingGroup to create and manage a Deployment @@ -37,12 +39,13 @@ class Moonshot::DeploymentMechanism::CodeDeploy # rubocop:disable ClassLength # CodeDeployDefault.OneAtATime. # rubocop:disable Metrics/ParameterLists def initialize( - asg: [], - optional_asg: [], - role: DEFAULT_ROLE_NAME, - app_name: nil, - group_name: nil, - config_name: 'CodeDeployDefault.OneAtATime') + asg: [], + optional_asg: [], + role: DEFAULT_ROLE_NAME, + app_name: nil, + group_name: nil, + config_name: 'CodeDeployDefault.OneAtATime' + ) @asg_logical_ids = Array(asg) @optional_asg_logical_ids = Array(optional_asg) @app_name = app_name @@ -51,6 +54,7 @@ def initialize( @codedeploy_config = config_name @ignore_app_stop_failures = false end + # rubocop:enable Metrics/ParameterLists def post_create_hook create_application_if_needed @@ -62,7 +66,7 @@ def post_create_hook def post_update_hook post_create_hook - unless deployment_group_ok? # rubocop:disable GuardClause + unless deployment_group_ok? # rubocop:disable Style/GuardClause delete_deployment_group create_deployment_group_if_needed end @@ -101,7 +105,7 @@ def post_delete_hook end def deploy_cli_hook(parser) - parser.on('--ignore-app-stop-failures', TrueClass, 'Continue deployment on ApplicationStop failures') do |v| # rubocop:disable LineLength + parser.on('--ignore-app-stop-failures', TrueClass, 'Continue deployment on ApplicationStop failures') do |v| puts "ignore = #{v}" @ignore_app_stop_failures = v end @@ -178,27 +182,23 @@ def load_auto_scaling_groups autoscaling_groups = [] @asg_logical_ids.each do |asg_logical_id| asg_name = stack.physical_id_for(asg_logical_id) - unless asg_name - raise "Could not find #{asg_logical_id} resource in Stack." - end + raise "Could not find #{asg_logical_id} resource in Stack." unless asg_name groups = as_client.describe_auto_scaling_groups( - auto_scaling_group_names: [asg_name]) - if groups.auto_scaling_groups.empty? - raise "Could not find ASG #{asg_name}." - end + auto_scaling_group_names: [asg_name] + ) + raise "Could not find ASG #{asg_name}." if groups.auto_scaling_groups.empty? autoscaling_groups.push(groups.auto_scaling_groups.first) end @optional_asg_logical_ids.each do |asg_logical_id| asg_name = stack.physical_id_for(asg_logical_id) next unless asg_name + groups = as_client.describe_auto_scaling_groups( auto_scaling_group_names: [asg_name] ) - unless groups.auto_scaling_groups.empty? - autoscaling_groups.push(groups.auto_scaling_groups.first) - end + autoscaling_groups.push(groups.auto_scaling_groups.first) unless groups.auto_scaling_groups.empty? end autoscaling_groups end @@ -220,13 +220,15 @@ def application_exists? def deployment_group cd_client.get_deployment_group( - application_name: app_name, deployment_group_name: group_name) + application_name: app_name, deployment_group_name: group_name + ) .deployment_group_info end def deployment_group_exists? cd_client.get_deployment_group( - application_name: app_name, deployment_group_name: group_name) + application_name: app_name, deployment_group_name: group_name + ) true rescue Aws::CodeDeploy::Errors::ApplicationDoesNotExistException, Aws::CodeDeploy::Errors::DeploymentGroupDoesNotExistException @@ -235,13 +237,13 @@ def deployment_group_exists? def deployment_group_ok? return false unless deployment_group_exists? + asgs = deployment_group.auto_scaling_groups return false unless asgs return false unless asgs.count == auto_scaling_groups.count + asgs.each do |asg| - if (auto_scaling_groups.find_index { |a| a.auto_scaling_group_name == asg.name }).nil? - return false - end + return false if (auto_scaling_groups.find_index { |a| a.auto_scaling_group_name == asg.name }).nil? end true end @@ -284,7 +286,8 @@ def delete_deployment_group ilog.start "Deleting #{pretty_deploy_group}." do |s| cd_client.delete_deployment_group( application_name: app_name, - deployment_group_name: group_name) + deployment_group_name: group_name + ) s.success end end @@ -294,7 +297,8 @@ def create_deployment_group application_name: app_name, deployment_group_name: group_name, service_role_arn: role.arn, - auto_scaling_groups: asg_names) + auto_scaling_groups: asg_names + ) end def wait_for_asg_capacity @@ -306,10 +310,11 @@ def wait_for_asg_capacity count = asg.instances.count { |i| i.lifecycle_state == 'InService' } if asg.desired_capacity == count asgs_at_capacity += 1 - s.continue "#{asg.auto_scaling_group_name} DesiredCapacity is #{asg.desired_capacity}, currently #{count} instance(s) are InService." # rubocop:disable LineLength + s.continue "#{asg.auto_scaling_group_name} DesiredCapacity is #{asg.desired_capacity}, currently #{count} instance(s) are InService." # rubocop:disable Layout/LineLength end end break if asgs.count == asgs_at_capacity + sleep 5 end @@ -327,7 +332,7 @@ def wait_for_deployment(id, step) case status when 'Created', 'Queued', 'InProgress' - step.continue "Waiting for Deployment #{id.blue} to complete, current status is '#{status}'." # rubocop:disable LineLength + step.continue "Waiting for Deployment #{id.blue} to complete, current status is '#{status}'." when 'Succeeded' step.success "Deployment #{id.blue} completed successfully!" break @@ -341,11 +346,11 @@ def wait_for_deployment(id, step) success end - def handle_deployment_failure(deployment_id) - instances = cd_client.list_deployment_instances(deployment_id: deployment_id) + def handle_deployment_failure(deployment_id) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + instances = cd_client.list_deployment_instances(deployment_id:) .instances_list.map do |instance_id| - cd_client.get_deployment_instance(deployment_id: deployment_id, - instance_id: instance_id) + cd_client.get_deployment_instance(deployment_id:, + instance_id:) end instances.map(&:instance_summary).each do |inst_summary| @@ -373,7 +378,7 @@ def revision_for_artifact_repo(artifact_repo, version_name) when Moonshot::ArtifactRepository::S3Bucket s3_revision_for(artifact_repo, version_name) when NilClass - raise 'Must specify an ArtifactRepository with CodeDeploy. Take a look at the S3Bucket example.' # rubocop:disable LineLength + raise 'Must specify an ArtifactRepository with CodeDeploy. Take a look at the S3Bucket example.' else raise "Cannot use #{artifact_repo.class} to deploy with CodeDeploy." end @@ -404,12 +409,12 @@ def create_deployment(artifact_repo, version_name) def doctor_check_code_deploy_role role success("#{@codedeploy_role} exists.") - rescue => e - help = <<-EOF -Error: #{e.message} + rescue StandardError => e + help = <<~EOF + Error: #{e.message} -For information on provisioning an account for use with CodeDeploy, see: -http://docs.aws.amazon.com/codedeploy/latest/userguide/how-to-create-service-role.html + For information on provisioning an account for use with CodeDeploy, see: + http://docs.aws.amazon.com/codedeploy/latest/userguide/how-to-create-service-role.html EOF critical("Could not find #{@codedeploy_role}, ", help) end @@ -419,7 +424,7 @@ def doctor_check_auto_scaling_resource_defined if stack.template.resource_names.include?(asg_logical_id) success("Resource '#{asg_logical_id}' exists in the CloudFormation template.") else - critical("Resource '#{asg_logical_id}' does not exist in the CloudFormation template!") # rubocop:disable LineLength + critical("Resource '#{asg_logical_id}' does not exist in the CloudFormation template!") end end end diff --git a/lib/moonshot/doctor_helper.rb b/lib/moonshot/doctor_helper.rb index f185235f..c802efa9 100644 --- a/lib/moonshot/doctor_helper.rb +++ b/lib/moonshot/doctor_helper.rb @@ -1,4 +1,5 @@ -# -*- coding: utf-8 -*- +# frozen_string_literal: true + require 'colorize' module Moonshot @@ -19,18 +20,16 @@ def run_all_checks puts puts self.class.name.split('::').last private_methods.each do |meth| - begin - send(meth) if meth =~ /^doctor_check_/ - rescue DoctorCritical - # Stop running checks in this Mechanism. - success = false - break - rescue => e - success = false - print ' ✗ '.red - puts "Exception while running check: #{e.class}: #{e.message.lines.first}" - break - end + send(meth) if meth =~ /^doctor_check_/ + rescue DoctorCritical + # Stop running checks in this Mechanism. + success = false + break + rescue StandardError => e + success = false + print ' ✗ '.red + puts "Exception while running check: #{e.class}: #{e.message.lines.first}" + break end success @@ -44,13 +43,13 @@ def success(str) def warning(str, additional_info = nil) print ' ? '.yellow puts str - additional_info.lines.each { |l| puts " #{l}" } if additional_info + additional_info&.lines&.each { |l| puts " #{l}" } end def critical(str, additional_info = nil) print ' ✗ '.red puts str - additional_info.lines.each { |l| puts " #{l}" } if additional_info + additional_info&.lines&.each { |l| puts " #{l}" } raise DoctorCritical end end diff --git a/lib/moonshot/dynamic_template.rb b/lib/moonshot/dynamic_template.rb index 48e3d51e..7e2f3a42 100644 --- a/lib/moonshot/dynamic_template.rb +++ b/lib/moonshot/dynamic_template.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'erb' module Moonshot @@ -51,6 +53,7 @@ def process def validate_destination_exists return unless File.file?(@destination) + raise TemplateExists, "Output file '#{@destination}' already exists." end diff --git a/lib/moonshot/interactive_logger_proxy.rb b/lib/moonshot/interactive_logger_proxy.rb index 4fb8b5b8..d0edaa03 100644 --- a/lib/moonshot/interactive_logger_proxy.rb +++ b/lib/moonshot/interactive_logger_proxy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'forwardable' module Moonshot @@ -10,8 +12,7 @@ def initialize(logger) @logger = logger end - def blank - end + def blank; end def continue(str = nil) @logger.info(str) if str @@ -21,8 +22,7 @@ def failure(str = 'Failure') @logger.error(str) end - def repaint - end + def repaint; end def success(str = 'Success') @logger.info(str) diff --git a/lib/moonshot/parameter_collection.rb b/lib/moonshot/parameter_collection.rb index edc90a77..2fccf901 100644 --- a/lib/moonshot/parameter_collection.rb +++ b/lib/moonshot/parameter_collection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot # A Rigid Hash-like structure that only accepts manipulation of # parameters defined in the Stack template. Anything else results in @@ -6,6 +8,7 @@ class ParameterCollection extend Forwardable def_delegators :@hash, :key?, :fetch, :[], :keys, :values + attr_reader :hash def self.from_template(template) obj = new diff --git a/lib/moonshot/parent_stack_parameter_loader.rb b/lib/moonshot/parent_stack_parameter_loader.rb index 468d3f17..edf6572b 100644 --- a/lib/moonshot/parent_stack_parameter_loader.rb +++ b/lib/moonshot/parent_stack_parameter_loader.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot class ParentStackParameterLoader def initialize(config) @@ -8,30 +10,32 @@ def load! @config.parent_stacks.each do |stack_name| count = 0 - resp = cf_client.describe_stacks(stack_name: stack_name) + resp = cf_client.describe_stacks(stack_name:) raise "Parent Stack #{stack_name} not found!" unless resp.stacks.size == 1 # If there is an input parameters matching a stack output, pass it. resp.stacks[0].outputs.each do |output| next unless @config.parameters.key?(output.output_key) + # Our Stack has a Parameter matching this output. Set it's # value to the Output's value. count += 1 @config.parameters.fetch(output.output_key).set(output.output_value) end - puts "Imported #{count} parameters from parent stack #{stack_name.blue}!" if count > 0 + puts "Imported #{count} parameters from parent stack #{stack_name.blue}!" if count.positive? end end def load_missing_only! @config.parent_stacks.each do |stack_name| - resp = cf_client.describe_stacks(stack_name: stack_name) + resp = cf_client.describe_stacks(stack_name:) raise "Parent Stack #{stack_name} not found!" unless resp.stacks.size == 1 # If there is an input parameters matching a stack output, pass it. resp.stacks[0].outputs.each do |output| next unless @config.parameters.key?(output.output_key) + # Our Stack has a Parameter matching this output. Set it's # value to the Output's value, but only if we don't already # have a previous value we're using. diff --git a/lib/moonshot/resources.rb b/lib/moonshot/resources.rb index 7a954c36..addbe62b 100644 --- a/lib/moonshot/resources.rb +++ b/lib/moonshot/resources.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot # Resources is a dependency container that holds references to instances # provided to a Mechanism (build, deploy, etc.). diff --git a/lib/moonshot/resources_helper.rb b/lib/moonshot/resources_helper.rb index f6d48409..37457abb 100644 --- a/lib/moonshot/resources_helper.rb +++ b/lib/moonshot/resources_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot # Provides shorthand methods for accessing resources provided by the Resources # container. @@ -8,16 +10,18 @@ module ResourcesHelper # TODO: Deprecate this interface. def log - @log ||= Logger.new(STDOUT) + @log ||= Logger.new($stdout) end def stack raise 'Resources not provided to Mechanism!' unless @resources + @resources.stack end def ilog raise 'Resources not provided to Mechanism!' unless @resources + @resources.ilog end end diff --git a/lib/moonshot/shell.rb b/lib/moonshot/shell.rb index 364e548e..eb373eb1 100644 --- a/lib/moonshot/shell.rb +++ b/lib/moonshot/shell.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'thor' require 'retriable' @@ -17,7 +19,7 @@ module Moonshot::Shell # Run a command, returning stdout. Stderr is suppressed unless the command # returns non-zero. - def sh_out(cmd, fail: true, stdin: '') + def sh_out(cmd, fail = true, stdin = '') # rubocop:disable Style/OptionalBooleanParameter r_in, w_in = IO.pipe r_out, w_out = IO.pipe r_err, w_err = IO.pipe @@ -46,20 +48,18 @@ def sh_out(cmd, fail: true, stdin: '') module_function :sh_out def shell - @thor_shell ||= Thor::Base.shell.new + @shell ||= Thor::Base.shell.new end Thor::Shell::Basic.public_instance_methods(false).each do |meth| define_method(meth) { |*args| shell.public_send(meth, *args) } end - def sh_step(cmd, args = {}) + def sh_step(cmd, **args) msg = args.delete(:msg) || cmd - if msg.length > (terminal_width - 18) - msg = "#{msg[0..(terminal_width - 22)]}..." - end + msg = "#{msg[0..(terminal_width - 22)]}..." if msg.length > (terminal_width - 18) ilog.start_threaded(msg) do |step| - out = sh_out(cmd, args) + out = sh_out(cmd, **args) yield step, out if block_given? step.success end @@ -73,9 +73,9 @@ def sh_step(cmd, args = {}) # @param opts [Hash] Options for retriable. # # @return [String] Stdout form the command. - def sh_retry(cmd, fail: true, stdin: '', opts: {}) + def sh_retry(cmd, fail = true, stdin = '', opts: {}) # rubocop:disable Style/OptionalBooleanParameter Retriable.retriable(DEFAULT_RETRY_OPTIONS.merge(opts)) do - out = sh_out(cmd, stdin: stdin) + out = sh_out(cmd, stdin:) yield out if block_given? out end diff --git a/lib/moonshot/ssh_command.rb b/lib/moonshot/ssh_command.rb index ad24ac5d..13efb0ec 100644 --- a/lib/moonshot/ssh_command.rb +++ b/lib/moonshot/ssh_command.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'thor' module Moonshot diff --git a/lib/moonshot/ssh_command_builder.rb b/lib/moonshot/ssh_command_builder.rb index dccca04e..40829e6f 100644 --- a/lib/moonshot/ssh_command_builder.rb +++ b/lib/moonshot/ssh_command_builder.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'shellwords' module Moonshot @@ -26,7 +28,7 @@ def instance_ip @instance_ip ||= Aws::EC2::Client.new .describe_instances(instance_ids: [@instance_id]) .reservations.first.instances.first.public_ip_address - rescue + rescue StandardError raise "Failed to determine public IP address for instance #{@instance_id}!" end end diff --git a/lib/moonshot/ssh_config.rb b/lib/moonshot/ssh_config.rb index 8f590f45..ae4791cf 100644 --- a/lib/moonshot/ssh_config.rb +++ b/lib/moonshot/ssh_config.rb @@ -1,8 +1,8 @@ +# frozen_string_literal: true + module Moonshot class SSHConfig - attr_accessor :ssh_identity_file - attr_accessor :ssh_user - attr_accessor :ssh_options + attr_accessor :ssh_identity_file, :ssh_user, :ssh_options def initialize @ssh_identity_file = ENV['MOONSHOT_SSH_KEY_FILE'] diff --git a/lib/moonshot/ssh_fork_executor.rb b/lib/moonshot/ssh_fork_executor.rb index 8fcf4796..348877a7 100644 --- a/lib/moonshot/ssh_fork_executor.rb +++ b/lib/moonshot/ssh_fork_executor.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'open3' module Moonshot diff --git a/lib/moonshot/ssh_target_selector.rb b/lib/moonshot/ssh_target_selector.rb index 2bb52f00..e1a8e5fc 100644 --- a/lib/moonshot/ssh_target_selector.rb +++ b/lib/moonshot/ssh_target_selector.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot # Choose a publically accessible instance to run commands on, given a Moonshot::Stack. class SSHTargetSelector @@ -6,7 +8,7 @@ def initialize(stack, asg_name: nil) @stack = stack end - def choose! + def choose! # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity groups = @stack.resources_of_type('AWS::AutoScaling::AutoScalingGroup') asg = if groups.count == 1 @@ -23,7 +25,7 @@ def choose! Aws::AutoScaling::Client.new.describe_auto_scaling_groups( auto_scaling_group_names: [asg.physical_resource_id] ).auto_scaling_groups.first.instances.map(&:instance_id).first - rescue => e + rescue StandardError => e raise "Failed to select an instance from the Auto Scaling Group: #{e.message}" end end diff --git a/lib/moonshot/stack.rb b/lib/moonshot/stack.rb index 2701534d..62a64bd9 100644 --- a/lib/moonshot/stack.rb +++ b/lib/moonshot/stack.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'yaml' module Moonshot @@ -5,12 +7,11 @@ module Moonshot # stores the state of the active stack running on AWS, but contains a # reference to the StackTemplate that would be applied with an update # action. - class Stack # rubocop:disable ClassLength + class Stack # rubocop:disable Metrics/ClassLength include CredsHelper include DoctorHelper - attr_reader :app_name - attr_reader :name + attr_reader :app_name, :name class << self def generate_name(config) @@ -20,13 +21,11 @@ def generate_name(config) def make_tags(config) default_tags = [ { key: 'moonshot_application', value: config.app_name }, - { key: 'moonshot_environment', value: config.environment_name }, + { key: 'moonshot_environment', value: config.environment_name } ] name = generate_name(config) - if config.additional_tag - default_tags << { key: config.additional_tag, value: name } - end + default_tags << { key: config.additional_tag, value: name } if config.additional_tag default_tags + config.extra_tags end @@ -131,7 +130,7 @@ def physical_id_for(logical_id) resource_summary = resource_summaries.find do |r| r.logical_resource_id == logical_id end - resource_summary.physical_resource_id if resource_summary + resource_summary&.physical_resource_id end # @return [Array] @@ -172,9 +171,11 @@ def load_template_file # Support the legacy file location from Moonshot 1.0. YamlStackTemplate.new( - File.join(@config.project_root, 'cloud_formation', "#{@config.app_name}.yml")), + File.join(@config.project_root, 'cloud_formation', "#{@config.app_name}.yml") + ), JsonStackTemplate.new( - File.join(@config.project_root, 'cloud_formation', "#{@config.app_name}.json")) + File.join(@config.project_root, 'cloud_formation', "#{@config.app_name}.json") + ) ] # If a template file has been specified in the config, look there first. @@ -186,6 +187,7 @@ def load_template_file template = templates.find(&:exist?) raise 'No template found in moonshot/template.{yml,json}!' unless template + template end @@ -204,9 +206,7 @@ def get_stack(name) end def upload_template_to_s3 - unless @config.template_s3_bucket - raise 'The S3 bucket to store the template in is not configured.' - end + raise 'The S3 bucket to store the template in is not configured.' unless @config.template_s3_bucket s3_object_key = "#{@name}-#{Time.now.getutc.to_i}-#{File.basename(template.filename)}" template_url = "http://#{@config.template_s3_bucket}.s3.amazonaws.com/#{s3_object_key}" @@ -226,7 +226,7 @@ def upload_template_to_s3 def create_stack parameters = { stack_name: @name, - capabilities: %w(CAPABILITY_IAM CAPABILITY_NAMED_IAM), + capabilities: %w[CAPABILITY_IAM CAPABILITY_NAMED_IAM], parameters: @config.parameters.values.map(&:to_cf), tags: make_tags } @@ -248,10 +248,10 @@ def new_change_set ].join('-') parameters = { - change_set_name: change_set_name, + change_set_name:, description: "Moonshot update command for application '#{Moonshot.config.app_name}'", stack_name: @name, - capabilities: %w(CAPABILITY_IAM CAPABILITY_NAMED_IAM), + capabilities: %w[CAPABILITY_IAM CAPABILITY_NAMED_IAM], parameters: @config.parameters.values.map(&:to_cf), tags: make_tags } @@ -276,36 +276,31 @@ def wait_for_stack_state(wait_target, past_tense_verb) events.show_only_errors unless @config.show_all_stack_events @ilog.start_threaded "Waiting for #{stack_name} to be successfully #{past_tense_verb}." do |s| - begin - cf_client.wait_until(wait_target, stack_name: stack_id) do |w| - w.delay = 10 - w.max_attempts = 360 # 60 minutes. - w.before_wait do |attempt, resp| - begin - events.latest_events.each { |e| @ilog.error(format_event(e)) } - # rubocop:disable Lint/HandleExceptions - rescue Aws::CloudFormation::Errors::ValidationError - # Do nothing. The above event logging block may result in - # a ValidationError while waiting for a stack to delete. - end - # rubocop:enable Lint/HandleExceptions - - if attempt == w.max_attempts - 1 - s.failure "#{stack_name} was not #{past_tense_verb} after 30 minutes." - result = false - - # We don't want the interactive logger to catch an exception. - throw :success - end - s.continue "Waiting for CloudFormation Stack to be successfully #{past_tense_verb}, current status '#{resp.stacks.first.stack_status}'." # rubocop:disable LineLength + cf_client.wait_until(wait_target, stack_name: stack_id) do |w| + w.delay = 10 + w.max_attempts = 360 # 60 minutes. + w.before_wait do |attempt, resp| + begin + events.latest_events.each { |e| @ilog.error(format_event(e)) } + rescue Aws::CloudFormation::Errors::ValidationError + # Do nothing. The above event logging block may result in + # a ValidationError while waiting for a stack to delete. end - end + if attempt == w.max_attempts - 1 + s.failure "#{stack_name} was not #{past_tense_verb} after 30 minutes." + result = false - s.success "#{stack_name} successfully #{past_tense_verb}." if result - rescue Aws::Waiters::Errors::FailureStateError - result = false - s.failure "#{stack_name} failed to update." + # We don't want the interactive logger to catch an exception. + throw :success + end + s.continue "Waiting for CloudFormation Stack to be successfully #{past_tense_verb}, current status '#{resp.stacks.first.stack_status}'." # rubocop:disable Layout/LineLength + end end + + s.success "#{stack_name} successfully #{past_tense_verb}." if result + rescue Aws::Waiters::Errors::FailureStateError + result = false + s.failure "#{stack_name} failed to update." end result @@ -347,7 +342,7 @@ def doctor_check_template_against_aws end cf_client.validate_template(validate_params) success('CloudFormation template is valid.') - rescue => e + rescue StandardError => e critical('Invalid CloudFormation template!', e.message) end @@ -371,6 +366,7 @@ def execute_change_set(change_set) success = wait_for_stack_state(:stack_update_complete, 'updated') raise 'Failed to update the CloudFormation Stack.' unless success + success end end diff --git a/lib/moonshot/stack_asg_printer.rb b/lib/moonshot/stack_asg_printer.rb index 79691182..e9b22f38 100644 --- a/lib/moonshot/stack_asg_printer.rb +++ b/lib/moonshot/stack_asg_printer.rb @@ -1,4 +1,5 @@ -# coding: utf-8 +# frozen_string_literal: true + require 'colorize' require 'ruby-duration' @@ -16,7 +17,8 @@ def initialize(stack, table) def print asgs.each do |asg| asg_info = as_client.describe_auto_scaling_groups( - auto_scaling_group_names: [asg.physical_resource_id]) + auto_scaling_group_names: [asg.physical_resource_id] + ) .auto_scaling_groups.first t_asg_info = @table.add_leaf("ASG: #{asg.logical_resource_id}") @@ -70,7 +72,7 @@ def health_color(health) # Get additional information about instances not returned by the ASG API. def get_addl_info(instance_ids) - resp = ec2_client.describe_instances(instance_ids: instance_ids) + resp = ec2_client.describe_instances(instance_ids:) data = {} resp.reservations.map(&:instances).flatten.each do |instance| @@ -93,7 +95,7 @@ def add_asg_info(table, asg_info) table.add_line "Desired Capacity is #{dc} (Min: #{min}, Max: #{max})." lbs = asg_info.load_balancer_names - table.add_line "Has #{lbs.count.to_s.blue} Load Balancer(s): #{lbs.map(&:blue).join(', ')}" # rubocop:disable LineLength + table.add_line "Has #{lbs.count.to_s.blue} Load Balancer(s): #{lbs.map(&:blue).join(', ')}" end def create_instance_table(asg_info) @@ -142,7 +144,8 @@ def uptime_format(launch_time) def add_recent_activity_leaf(table, asg_name) recent = table.add_leaf('Recent Activity') resp = as_client.describe_scaling_activities( - auto_scaling_group_name: asg_name).activities + auto_scaling_group_name: asg_name + ).activities rows = resp.sort_by(&:start_time).reverse.first(10).map do |activity| row_for_activity(activity) diff --git a/lib/moonshot/stack_config.rb b/lib/moonshot/stack_config.rb index 7093ce1a..86cf2018 100644 --- a/lib/moonshot/stack_config.rb +++ b/lib/moonshot/stack_config.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + module Moonshot # Configuration for the Moonshot::Stack class. class StackConfig - attr_accessor :parent_stacks - attr_accessor :show_all_events + attr_accessor :parent_stacks, :show_all_events def initialize @parent_stacks = [] diff --git a/lib/moonshot/stack_events_poller.rb b/lib/moonshot/stack_events_poller.rb index 46a90092..e5c8080d 100644 --- a/lib/moonshot/stack_events_poller.rb +++ b/lib/moonshot/stack_events_poller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot # The StackEventsPoller queries DescribeStackEvents every time #latest_events # is invoked, filtering out events that have already been returned. It can @@ -32,7 +34,7 @@ def latest_events def filter_events(events) if @errors_only events.select do |event| - %w(CREATE_FAILED UPDATE_FAILED DELETE_FAILED).include?(event.resource_status) + %w[CREATE_FAILED UPDATE_FAILED DELETE_FAILED].include?(event.resource_status) end else events diff --git a/lib/moonshot/stack_list_printer.rb b/lib/moonshot/stack_list_printer.rb index 30e5774c..4791e253 100644 --- a/lib/moonshot/stack_list_printer.rb +++ b/lib/moonshot/stack_list_printer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot class StackListPrinter attr_accessor :stacks diff --git a/lib/moonshot/stack_lister.rb b/lib/moonshot/stack_lister.rb index 1203fd69..eacfefd5 100644 --- a/lib/moonshot/stack_lister.rb +++ b/lib/moonshot/stack_lister.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot # The StackLister is world renoun for it's ability to list stacks. class StackLister @@ -9,11 +11,11 @@ def initialize(app_name) end # rubocop:disable Metrics/AbcSize - def list + def list # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity result = [] next_token = nil loop do - resp = cf_client.describe_stacks(next_token: next_token) + resp = cf_client.describe_stacks(next_token:) resp.stacks.each do |stack| app_tag = stack.tags.find { |t| t.key == 'moonshot_application' } env_tag = stack.tags.find { |t| t.key == 'moonshot_environment' } @@ -22,15 +24,17 @@ def list if app_tag && app_tag.value == Moonshot.config.app_name result << EnvironmentDescription.new(env_tag.value, stack.creation_time, stack.stack_status) - elsif legacy_tag && legacy_tag.value.start_with?(Moonshot.config.app_name) + elsif legacy_tag&.value&.start_with?(Moonshot.config.app_name) result << EnvironmentDescription.new(legacy_tag.value, stack.creation_time, stack.stack_status) end end break unless resp.next_token + next_token = resp.next_token end result.sort_by(&:name) end + # rubocop:enable Metrics/AbcSize end end diff --git a/lib/moonshot/stack_output_printer.rb b/lib/moonshot/stack_output_printer.rb index 59a67bf1..87e68f19 100644 --- a/lib/moonshot/stack_output_printer.rb +++ b/lib/moonshot/stack_output_printer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot # Display the stack outputs to the user. class StackOutputPrinter diff --git a/lib/moonshot/stack_parameter.rb b/lib/moonshot/stack_parameter.rb index d7c9df66..b4087113 100644 --- a/lib/moonshot/stack_parameter.rb +++ b/lib/moonshot/stack_parameter.rb @@ -1,8 +1,8 @@ +# frozen_string_literal: true + module Moonshot class StackParameter - attr_reader :name - attr_reader :default - attr_reader :description + attr_reader :name, :default, :description def initialize(name, default: nil, use_previous: false, description: '') @default = default @@ -32,9 +32,7 @@ def set(value) end def use_previous!(value) - if @value - raise "Value already set for StackParameter #{@name}, cannot use previous value!" - end + raise "Value already set for StackParameter #{@name}, cannot use previous value!" if @value # Make the current value available to plugins. @value = value @@ -42,9 +40,7 @@ def use_previous!(value) end def value - unless @value || default? - raise "No value set and no default for StackParameter #{@name}!" - end + raise "No value set and no default for StackParameter #{@name}!" unless @value || default? @value || default end diff --git a/lib/moonshot/stack_parameter_printer.rb b/lib/moonshot/stack_parameter_printer.rb index 7e7e0d2c..8fd31200 100644 --- a/lib/moonshot/stack_parameter_printer.rb +++ b/lib/moonshot/stack_parameter_printer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot # Displays information about existing stack parameters to the user, with # information on what a stack update would do. @@ -18,7 +20,7 @@ def print def format_value(value) if value.size > 60 - value[0..60] + '...' + "#{value[0..60]}..." else value end diff --git a/lib/moonshot/stack_template.rb b/lib/moonshot/stack_template.rb index 165878f2..e4a971ce 100644 --- a/lib/moonshot/stack_template.rb +++ b/lib/moonshot/stack_template.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot # A StackTemplate loads the template from disk and stores information # about it. diff --git a/lib/moonshot/task.rb b/lib/moonshot/task.rb index 68ec97db..3393a47f 100644 --- a/lib/moonshot/task.rb +++ b/lib/moonshot/task.rb @@ -1,6 +1,9 @@ +# frozen_string_literal: true + module Moonshot class Task attr_reader :name, :desc, :block + def initialize(name, desc, &block) @name = name.to_sym @desc = desc diff --git a/lib/moonshot/tools/asg_rollout.rb b/lib/moonshot/tools/asg_rollout.rb index 0986ea90..aa40479d 100644 --- a/lib/moonshot/tools/asg_rollout.rb +++ b/lib/moonshot/tools/asg_rollout.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + module Moonshot module Tools - class ASGRollout # rubocop:disable ClassLength + class ASGRollout # rubocop:disable Metrics/ClassLength attr_accessor :config def initialize(controller:, logical_id:) @@ -16,7 +18,7 @@ def run! new_instance = wait_for_new_instance begin wait_for_in_service(new_instance) - rescue + rescue StandardError next end break @@ -74,6 +76,7 @@ def wait_for_in_service(new_instance) raise "Instance #{new_instance.blue} went OutOfService while waiting to join..." end break if instance_health.in_service? + s.continue "Instance #{new_instance.blue} is #{instance_health}..." sleep @config.instance_health_delay end @@ -83,22 +86,22 @@ def wait_for_in_service(new_instance) end def run_pre_detach(instance) - if @config.pre_detach - log.start_threaded "Running PreDetach hook on #{instance.blue}..." do |s| - he = HookExecEnvironment.new(@controller.config, instance) - if false == @config.pre_detach.call(he) - s.failure "PreDetach hook failed for #{instance.blue}!" - raise "PreDetach hook failed for #{instance.blue}!" - end + return unless @config.pre_detach - s.success "PreDetach hook complete for #{instance.blue}!" + log.start_threaded "Running PreDetach hook on #{instance.blue}..." do |s| + he = HookExecEnvironment.new(@controller.config, instance) + if @config.pre_detach.call(he) == false + s.failure "PreDetach hook failed for #{instance.blue}!" + raise "PreDetach hook failed for #{instance.blue}!" end + + s.success "PreDetach hook complete for #{instance.blue}!" end end def detach(instance, decrement:) log.start_threaded "Detaching instance #{instance.blue}..." do |s| - asg.detach_instance(instance, decrement: decrement) + asg.detach_instance(instance, decrement:) if decrement s.success "Detached instance #{instance.blue}, and decremented DesiredCapacity." @@ -115,6 +118,7 @@ def wait_for_out_of_service(instance) loop do instance_health = asg.instance_health(instance) break if instance_health.out_of_service? + s.continue "Instance #{instance.blue} is #{instance_health}..." sleep @config.instance_health_delay end @@ -155,9 +159,7 @@ def asg return @asg if @asg asg_name = @controller.stack.physical_id_for(@logical_id) - unless asg_name - raise "Could not find Auto Scaling Group #{@logical_id}!" - end + raise "Could not find Auto Scaling Group #{@logical_id}!" unless asg_name @asg ||= ASGRollout::ASG.new(asg_name) end diff --git a/lib/moonshot/tools/asg_rollout/asg.rb b/lib/moonshot/tools/asg_rollout/asg.rb index 44332572..9ecde519 100644 --- a/lib/moonshot/tools/asg_rollout/asg.rb +++ b/lib/moonshot/tools/asg_rollout/asg.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Tools class ASGRollout @@ -20,14 +22,15 @@ def set_max_and_desired(max, desired) autoscaling.update_auto_scaling_group( auto_scaling_group_name: @name, max_size: max, - desired_capacity: desired) + desired_capacity: desired + ) end def non_conforming_instances asg = load_asg asg.instances - .select { |i| i.launch_configuration_name != asg.launch_configuration_name } + .reject { |i| i.launch_configuration_name == asg.launch_configuration_name } .map(&:instance_id) end @@ -59,17 +62,17 @@ def detach_instance(id, decrement:) resp = autoscaling.detach_instances( auto_scaling_group_name: @name, instance_ids: [id], - should_decrement_desired_capacity: decrement) + should_decrement_desired_capacity: decrement + ) activity = resp.activities.first - unless activity - raise 'Did not receive Activity from DetachInstances call!' - end + raise 'Did not receive Activity from DetachInstances call!' unless activity # Wait for the detach activity to complete: loop do resp = autoscaling.describe_scaling_activities( - auto_scaling_group_name: @name) + auto_scaling_group_name: @name + ) current_status = resp.activities .find { |a| a.activity_id == activity.activity_id } @@ -97,7 +100,8 @@ def instance_health(id) def asg_instance_state(id) resp = autoscaling.describe_auto_scaling_instances( - instance_ids: [id]) + instance_ids: [id] + ) instance_info = resp.auto_scaling_instances.first return 'Missing' unless instance_info @@ -110,12 +114,11 @@ def elb_instance_state(id) load_balancer_name: elb_name, instances: [ { instance_id: id } - ]) + ] + ) instance_info = resp.instance_states.first - unless instance_info - raise "Failed to call DescribeInstanceHealth for #{id}!" - end + raise "Failed to call DescribeInstanceHealth for #{id}!" unless instance_info instance_info.state rescue Aws::ElasticLoadBalancing::Errors::InvalidInstance @@ -133,11 +136,10 @@ def loadbalancing def load_asg resp = autoscaling.describe_auto_scaling_groups( - auto_scaling_group_names: [@name]) + auto_scaling_group_names: [@name] + ) - if resp.auto_scaling_groups.empty? - raise "Failed to call DescribeAutoScalingGroups for #{@name}!" - end + raise "Failed to call DescribeAutoScalingGroups for #{@name}!" if resp.auto_scaling_groups.empty? asg = resp.auto_scaling_groups.first @last_seen_ids = asg.instances.map(&:instance_id) @@ -149,9 +151,7 @@ def elb_name return @elb_name if @elb_name asg = load_asg - if asg.load_balancer_names.size > 1 - raise 'ASGRollout does not support configurations with multiple ELBs!' - end + raise 'ASGRollout does not support configurations with multiple ELBs!' if asg.load_balancer_names.size > 1 @elb_name ||= asg.load_balancer_names.first end diff --git a/lib/moonshot/tools/asg_rollout/asg_instance.rb b/lib/moonshot/tools/asg_rollout/asg_instance.rb index f4c3e32c..a86ff7d3 100644 --- a/lib/moonshot/tools/asg_rollout/asg_instance.rb +++ b/lib/moonshot/tools/asg_rollout/asg_instance.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Tools class ASGRollout diff --git a/lib/moonshot/tools/asg_rollout/hook_exec_environment.rb b/lib/moonshot/tools/asg_rollout/hook_exec_environment.rb index 7ed13efc..761785de 100644 --- a/lib/moonshot/tools/asg_rollout/hook_exec_environment.rb +++ b/lib/moonshot/tools/asg_rollout/hook_exec_environment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'moonshot/ssh_fork_executor' module Moonshot diff --git a/lib/moonshot/tools/asg_rollout/instance_health.rb b/lib/moonshot/tools/asg_rollout/instance_health.rb index 23cad106..09c67ace 100644 --- a/lib/moonshot/tools/asg_rollout/instance_health.rb +++ b/lib/moonshot/tools/asg_rollout/instance_health.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Tools class ASGRollout diff --git a/lib/moonshot/tools/asg_rollout_config.rb b/lib/moonshot/tools/asg_rollout_config.rb index 84177034..0b12a5fd 100644 --- a/lib/moonshot/tools/asg_rollout_config.rb +++ b/lib/moonshot/tools/asg_rollout_config.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Tools class ASGRolloutConfig diff --git a/lib/moonshot/unicode_table.rb b/lib/moonshot/unicode_table.rb index 917d2ac5..fb41e092 100644 --- a/lib/moonshot/unicode_table.rb +++ b/lib/moonshot/unicode_table.rb @@ -1,4 +1,4 @@ -# coding: utf-8 +# frozen_string_literal: true require 'colorize' @@ -36,13 +36,13 @@ def add_table(table) table.each { |line| add_line(format(format, *line)) } end - def draw(depth = 1, first = true) + def draw(depth = 1, first = true) # rubocop:disable Style/OptionalBooleanParameter print first ? '┌' : '├' print '─' * depth - puts ' ' << @name.light_black + puts " #{@name.light_black}" @lines = [''] + @lines + [''] @lines.each do |line| - puts '│' << (' ' * depth) << line + puts "│#{' ' * depth}#{line}" end @children.each do |child| child.draw(depth + 1, false) diff --git a/lib/moonshot/yaml_stack_template.rb b/lib/moonshot/yaml_stack_template.rb index 72e57022..9ebb825b 100644 --- a/lib/moonshot/yaml_stack_template.rb +++ b/lib/moonshot/yaml_stack_template.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'yaml' module Moonshot diff --git a/lib/plugins/backup.rb b/lib/plugins/backup.rb index 67e2b1b5..e5136cf4 100644 --- a/lib/plugins/backup.rb +++ b/lib/plugins/backup.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rubygems/package' require 'zlib' require 'yaml' @@ -20,7 +22,7 @@ class Backup # rubocop:disable Metrics/ClassLength def initialize yield self if block_given? validate_configuration - @target_name ||= '%{app_name}_%{timestamp}_%{user}.tar.gz' + @target_name ||= '%s_%s_%s.tar.gz' end # Factory method to create preconfigured Backup plugins. Uploads current @@ -29,11 +31,12 @@ def initialize # @return [Backup] configured backup object def self.to_bucket(bucket) raise ArgumentError if bucket.nil? || bucket.empty? + Moonshot::Plugins::Backup.new do |b| b.bucket = bucket b.backup_parameters = true b.backup_template = true - b.hooks = [:post_create, :post_update] + b.hooks = %i[post_create post_update] end end @@ -53,27 +56,25 @@ def backup(resources) return if @target_bucket.nil? resources.ilog.start("#{log_message} in progress.") do |s| - begin - tar_out = tar(@files) - zip_out = zip(tar_out) - upload(zip_out) - - s.success("#{log_message} succeeded.") - rescue => e - s.failure("#{log_message} failed: #{e}") - ensure - tar_out.close unless tar_out.nil? - zip_out.close unless zip_out.nil? - end + tar_out = tar(@files) + zip_out = zip(tar_out) + upload(zip_out) + + s.success("#{log_message} succeeded.") + rescue StandardError => e + s.failure("#{log_message} failed: #{e}") + ensure + tar_out&.close + zip_out&.close end end # Dynamically responding to hooks supplied in the constructor - def method_missing(method_name, *args, &block) + def method_missing(method_name, *args, &block) # rubocop:disable Style/MissingRespondToMissing @hooks.include?(method_name) ? backup(*args) : super end - def respond_to?(method_name, include_private = false) + def respond_to?(method_name, include_private: false) @hooks.include?(method_name) || super end @@ -110,7 +111,7 @@ def tar(target_files) # adding template file if @backup_template - template_file_path = render('cloud_formation/%{app_name}.json') + template_file_path = render('cloud_formation/%s.json') add_file_to_tar(writer, template_file_path) end end @@ -123,12 +124,10 @@ def tar(target_files) # @param writer [TarWriter] # @param file_name [String] def add_file_to_tar(writer, file_name) - writer.add_file(File.basename(file_name), 0644) do |io| - begin - File.open(file_name, 'r') { |f| io.write(f.read) } - rescue Errno::ENOENT - warn "'#{file_name}' was not found." - end + writer.add_file(File.basename(file_name), 0o644) do |io| + File.open(file_name, 'r') { |f| io.write(f.read) } + rescue Errno::ENOENT + warn "'#{file_name}' was not found." end end @@ -139,7 +138,7 @@ def add_file_to_tar(writer, file_name) # @param target_filename [String] # @param content [String] def add_str_to_tar(writer, target_filename, content) - writer.add_file(File.basename(target_filename), 0644) do |io| + writer.add_file(File.basename(target_filename), 0o644) do |io| io.write(content.to_yaml) end end @@ -165,11 +164,13 @@ def zip(io_tar) def upload(io_zip) opts = {} opts[:region] = @bucket_region if @bucket_region - s3_client(opts).put_object( - acl: 'private', - bucket: @target_bucket, - key: @target_name, - body: io_zip + s3_client(**opts).put_object( + { + acl: 'private', + bucket: @target_bucket, + key: @target_name, + body: io_zip + } ) end @@ -196,17 +197,13 @@ def iam_account end def define_bucket - case # returning already calculated bucket name - when @target_bucket - @target_bucket + return @target_bucket if @target_bucket # single bucket for all accounts - when @bucket - @bucket + return @bucket if @bucket + # calculating bucket based on account name - when @buckets - bucket_by_account(iam_account) - end + bucket_by_account(iam_account) if @buckets end def bucket_by_account(account) diff --git a/lib/plugins/code_deploy_setup.rb b/lib/plugins/code_deploy_setup.rb index dd25fc6d..9959711c 100644 --- a/lib/plugins/code_deploy_setup.rb +++ b/lib/plugins/code_deploy_setup.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module Plugins # Plugin to ensure CodeDeploy has all necessary S3 buckets created. @@ -33,11 +35,11 @@ def bucket_prefix # Create an S3 bucket in each supported region for CodeDeploy def setup_code_deploy_s3_buckets @regions.uniq.each do |region| - client = s3_client(region: region) + client = s3_client(region:) name = bucket_name(region) bucket = Aws::S3::Bucket.new( name, - client: client + client: ) bucket.create unless bucket.exists? end diff --git a/lib/plugins/dynamic_template.rb b/lib/plugins/dynamic_template.rb index e15b8ffd..cc252029 100644 --- a/lib/plugins/dynamic_template.rb +++ b/lib/plugins/dynamic_template.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + module Moonshot module Plugins class DynamicTemplate def initialize(source:, parameters:, destination:) @dynamic_template = ::Moonshot::DynamicTemplate.new( - source: source, - parameters: parameters, - destination: destination + source:, + parameters:, + destination: ) end @@ -14,7 +16,7 @@ def run_hook end def cli_hook(parser) - parser.on('--template-file=FILE', 'Override the path to the CloudFormation template.') do |v| # rubocop:disable LineLength + parser.on('--template-file=FILE', 'Override the path to the CloudFormation template.') do |v| @dynamic_template.destination = v Moonshot.config.template_file = v end diff --git a/lib/plugins/encrypted_parameters.rb b/lib/plugins/encrypted_parameters.rb index e8ce381f..ac367815 100644 --- a/lib/plugins/encrypted_parameters.rb +++ b/lib/plugins/encrypted_parameters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This plugin encrypts parameters of the stack using a KMS Key, # storing and passing the key used to the stack as a parameter as # well. The resources in the stack can then use that KMS Key to @@ -96,13 +98,13 @@ def find_or_create_kms_key @ilog.start_threaded "Checking for KMS Key #{@kms_key_parameter_name}" do |s| if Moonshot.config.parameters.key?(@kms_key_parameter_name) - if 'Auto' == Moonshot.config.parameters[@kms_key_parameter_name].value + if Moonshot.config.parameters[@kms_key_parameter_name].value == 'Auto' s.continue "Auto-generating KMS Key for #{@kms_key_parameter_name.blue}... " key_arn = KmsKey.create.arn Moonshot.config.parameters[@kms_key_parameter_name].set(key_arn) s.success "Created a new KMS Key for #{@kms_key_parameter_name.blue}!" else - kms=KmsKey.new(Moonshot.config.parameters[@kms_key_parameter_name].value) + kms = KmsKey.new(Moonshot.config.parameters[@kms_key_parameter_name].value) key_arn = kms.arn kms.update s.success "Using existing KMS Key for #{@kms_key_parameter_name.blue}!" diff --git a/lib/plugins/encrypted_parameters/kms_key.rb b/lib/plugins/encrypted_parameters/kms_key.rb index 62e8fa91..6dfcf4dd 100644 --- a/lib/plugins/encrypted_parameters/kms_key.rb +++ b/lib/plugins/encrypted_parameters/kms_key.rb @@ -1,4 +1,6 @@ -require_relative '../../moonshot/stack.rb' +# frozen_string_literal: true + +require_relative '../../moonshot/stack' module Moonshot module Plugins @@ -6,19 +8,20 @@ class EncryptedParameters # Class that manages KMS keys in AWS. class KmsKey attr_reader :arn + class << self def create standard_tags = stack_tags resp = Aws::KMS::Client.new.create_key({ - tags: standard_tags, # An array of tags. - }) + tags: standard_tags # An array of tags. + }) arn = resp.key_metadata.arn new(arn) end def stack_tags tags = Moonshot::Stack.make_tags(Moonshot.config) - tags.map { |tag| { tag_key: tag[:key], tag_value: tag[:value] } } + tags.map { |tag| { tag_key: tag[:key], tag_value: tag[:value] } } end end @@ -30,9 +33,9 @@ def initialize(arn) def update standard_tags = self.class.stack_tags @kms_client.tag_resource({ - key_id: @arn, # arn of the CMK being tagged - tags: standard_tags, # An array of tags. - }) + key_id: @arn, # arn of the CMK being tagged + tags: standard_tags # An array of tags. + }) end def delete diff --git a/lib/plugins/encrypted_parameters/parameter_encrypter.rb b/lib/plugins/encrypted_parameters/parameter_encrypter.rb index b5c1d0fb..344be8ae 100644 --- a/lib/plugins/encrypted_parameters/parameter_encrypter.rb +++ b/lib/plugins/encrypted_parameters/parameter_encrypter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'base64' module Moonshot module Plugins diff --git a/lib/plugins/rotate_asg_instances/asg.rb b/lib/plugins/rotate_asg_instances/asg.rb index e50568f7..4031c9e2 100644 --- a/lib/plugins/rotate_asg_instances/asg.rb +++ b/lib/plugins/rotate_asg_instances/asg.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module RotateAsgInstances class ASG # rubocop:disable Metrics/ClassLength @@ -67,7 +69,6 @@ def identify_outdated_instances def with_scale_up scaled_up = scale_up_if_possible yield - rescue StandardError => e @ilog.error("Failure encountered during scale up to the desired capacity: #{e.message}") ensure @@ -110,7 +111,7 @@ def outdated_volumes(outdated_instances) begin inst = Aws::EC2::Instance.new(id: i.id) first_block_device = inst.block_device_mappings.first - volumes << first_block_device.ebs.volume_id if first_block_device + volumes << first_block_device[:ebs][:volume_id] if first_block_device rescue StandardError => e # We're catching all errors here, because failing to reap a volume # is not a critical error, will not cause issues with the update. @@ -187,6 +188,7 @@ def detach_instance(instance) true rescue Aws::AutoScaling::Errors::ValidationError => e raise e unless e.message.include?('is not part of Auto Scaling group') + wait_for_capacity false rescue StandardError => e @@ -203,7 +205,7 @@ def detach_instance(instance) def reattach_instance(instance) instance.load return unless instance.data.nil? \ - || %w(Detached Detaching).include?(instance.lifecycle_state) + || %w[Detached Detaching].include?(instance.lifecycle_state) until instance.data.nil? || instance.lifecycle_state == 'Detached' sleep 10 @@ -218,6 +220,7 @@ def reattach_instance(instance) # List of instances to terminate. Defaults to all instances with outdated # launch configurations. def terminate_instances(shutdown_instances) + @ilog.info("Terminate instances: #{shutdown_instances}") if shutdown_instances.any? @step.continue( "Terminating #{shutdown_instances.size} outdated instances..." @@ -231,7 +234,7 @@ def terminate_instances(shutdown_instances) next end - next unless %w(stopping stopped).include?(instance.state.name) + next unless %w[stopping stopped].include?(instance.state[:name]) instance.wait_until_stopped @@ -249,15 +252,13 @@ def scale_asg(new_desired_capacity) def reap_volumes(volumes) volumes.each do |volume_id| - begin - @step.continue("Deleting volume: #{volume_id}") - ec2_client(region: ENV['AWS_REGION']) - .delete_volume(volume_id: volume_id) - rescue StandardError => e - # We're catching all errors here, because failing to reap a volume - # is not a critical error, will not cause issues with the release. - @step.failure("Failed to delete volume #{volume_id}: #{e.message}") - end + @step.continue("Deleting volume: #{volume_id}") + ec2_client(region: ENV['AWS_REGION']) + .delete_volume(volume_id:) + rescue StandardError => e + # We're catching all errors here, because failing to reap a volume + # is not a critical error, will not cause issues with the release. + @step.failure("Failed to delete volume #{volume_id}: #{e.message}") end end @@ -277,7 +278,7 @@ def wait_for_capacity @step.continue("Instances: #{instances.join(', ')}") end - asg.reload.wait_until(before_wait: before_wait, max_attempts: 60, + asg.reload.wait_until(before_wait:, max_attempts: 60, delay: 30) do |a| instances_up = a.instances.select do |i| i.lifecycle_state == 'InService' @@ -292,8 +293,9 @@ def wait_for_capacity # # @param id [String] ID of the instance to terminate. def shutdown_instance(id) - instance = Aws::EC2::Instance.new(id: id) + instance = Aws::EC2::Instance.new(id:) return if instance_in_terminal_state?(instance) + @ssh.exec('sudo shutdown -h now', id) instance.wait_until_stopped end @@ -304,12 +306,13 @@ def instance_in_terminal_state?(instance) elsif instance.is_a?(Aws::AutoScaling::Instance) check_asg_instance(instance) end - %w(Terminating Terminated).include?(state) + %w[Terminating Terminated].include?(state) end def check_ec2_instance(instance) + @ilog.info("Check ec2 instance: #{instance}") if instance.exists? - instance.state.name + instance.state[:name] else 'Terminated' end diff --git a/lib/plugins/rotate_asg_instances/ssh.rb b/lib/plugins/rotate_asg_instances/ssh.rb index e23d079c..ae29067a 100644 --- a/lib/plugins/rotate_asg_instances/ssh.rb +++ b/lib/plugins/rotate_asg_instances/ssh.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Moonshot module RotateAsgInstances class SSHValidationError < StandardError @@ -15,6 +17,7 @@ def test_ssh_connection(instance_id) # rubocop:disable Style/RaiseArgs raise SSHValidationError.new(response) unless response.exitstatus.zero? + # rubocop:enable Style/RaiseArgs end end diff --git a/moonshot.gemspec b/moonshot.gemspec index a177dd49..0a4daff6 100644 --- a/moonshot.gemspec +++ b/moonshot.gemspec @@ -1,6 +1,8 @@ +# frozen_string_literal: true + Gem::Specification.new do |s| s.name = 'moonshot' - s.version = '2.0.0.beta6' + s.version = '3.0.0' s.licenses = ['Apache-2.0'] s.summary = 'A library and CLI tool for launching services into AWS' s.description = 'A library and CLI tool for launching services into AWS.' @@ -14,6 +16,8 @@ Gem::Specification.new do |s| s.homepage = 'https://github.com/acquia/moonshot' s.add_dependency('aws-sdk', '~> 2.0', '>= 2.2.0') + s.required_ruby_version = '>= 3.1.2' + s.add_dependency('activesupport') s.add_dependency('colorize') s.add_dependency('highline') diff --git a/sample/Gemfile b/sample/Gemfile index 06e72e9a..c8e8217f 100644 --- a/sample/Gemfile +++ b/sample/Gemfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + source 'https://rubygems.org' gem 'moonshot', '~> 0.7.0' diff --git a/spec/moonshot/commands/build_spec.rb b/spec/moonshot/commands/build_spec.rb index bf7424e7..addcf919 100644 --- a/spec/moonshot/commands/build_spec.rb +++ b/spec/moonshot/commands/build_spec.rb @@ -5,7 +5,7 @@ parser = cli_dispatcher.send(:build_parser, subject) expect { parser.parse(%w(--skip-ci-status)) }.to raise_error(RuntimeError) end - + it 'should not raise RuntimeError when send --skip-ci-status param with GithubRelease plugin' do Moonshot.config = Moonshot::ControllerConfig.new Moonshot.config do |c| @@ -14,6 +14,6 @@ cli_dispatcher = Moonshot::CommandLineDispatcher.new('build', subject, {}) parser = cli_dispatcher.send(:build_parser, subject) expect { parser.parse(%w(--skip-ci-status)) }.to_not raise_error - end - + end + end diff --git a/spec/moonshot/shell_spec.rb b/spec/moonshot/shell_spec.rb index 28de2346..c18ccbe3 100644 --- a/spec/moonshot/shell_spec.rb +++ b/spec/moonshot/shell_spec.rb @@ -27,7 +27,7 @@ module Moonshot end it 'should not raise if fail is disabled.' do - sh_out('false', fail: false) + sh_out('false', false) end end diff --git a/spec/moonshot/stack_spec.rb b/spec/moonshot/stack_spec.rb index 2a4068d2..4a243008 100644 --- a/spec/moonshot/stack_spec.rb +++ b/spec/moonshot/stack_spec.rb @@ -97,7 +97,7 @@ end context 'when template_s3_bucket is set' do - let(:time_obj) { Time.new('2017-11-07 12:00:00 +0000') } + let(:time_obj) { Time.parse('2017-11-07 12:00:00 +0000') } before(:each) do config.template_s3_bucket = 'rspec-bucket'