ey-core 3.0.5 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/Gemfile +0 -7
 - data/bin/ey-core +1 -1
 - data/ey-core.gemspec +15 -1
 - data/lib/ey-core/cli.rb +12 -114
 - data/lib/ey-core/cli/accounts.rb +9 -0
 - data/lib/ey-core/cli/applications.rb +16 -0
 - data/lib/ey-core/cli/console.rb +14 -0
 - data/lib/ey-core/cli/current_user.rb +8 -0
 - data/lib/ey-core/cli/deploy.rb +65 -0
 - data/lib/ey-core/cli/environments.rb +17 -0
 - data/lib/ey-core/cli/errors.rb +7 -0
 - data/lib/ey-core/cli/init.rb +11 -0
 - data/lib/ey-core/cli/login.rb +26 -0
 - data/lib/ey-core/cli/logout.rb +14 -0
 - data/lib/ey-core/cli/logs.rb +40 -0
 - data/lib/ey-core/cli/recipes.rb +92 -0
 - data/lib/ey-core/cli/recipes/apply.rb +34 -0
 - data/lib/ey-core/cli/recipes/download.rb +26 -0
 - data/lib/ey-core/cli/recipes/upload.rb +27 -0
 - data/lib/ey-core/cli/scp.rb +11 -0
 - data/lib/ey-core/cli/servers.rb +19 -0
 - data/lib/ey-core/cli/ssh.rb +94 -0
 - data/lib/ey-core/cli/status.rb +20 -0
 - data/lib/ey-core/cli/subcommand.rb +114 -0
 - data/lib/ey-core/cli/timeout_deploy.rb +28 -0
 - data/lib/ey-core/cli/version.rb +8 -0
 - data/lib/ey-core/cli/web.rb +10 -0
 - data/lib/ey-core/cli/web/disable.rb +23 -0
 - data/lib/ey-core/cli/web/enable.rb +23 -0
 - data/lib/ey-core/cli/web/restart.rb +23 -0
 - data/lib/ey-core/cli/whoami.rb +4 -0
 - data/lib/ey-core/client.rb +9 -0
 - data/lib/ey-core/client/mock.rb +1 -0
 - data/lib/ey-core/client/real.rb +4 -4
 - data/lib/ey-core/collections/deployments.rb +8 -0
 - data/lib/ey-core/models/account.rb +1 -0
 - data/lib/ey-core/models/deployment.rb +23 -0
 - data/lib/ey-core/models/environment.rb +37 -0
 - data/lib/ey-core/requests/change_environment_maintenance.rb +38 -0
 - data/lib/ey-core/requests/create_environment.rb +3 -0
 - data/lib/ey-core/requests/deploy_environment_application.rb +17 -0
 - data/lib/ey-core/requests/get_deployment.rb +19 -0
 - data/lib/ey-core/requests/get_deployments.rb +29 -0
 - data/lib/ey-core/requests/get_token_by_login.rb +30 -0
 - data/lib/ey-core/requests/restart_environment_app_servers.rb +38 -0
 - data/lib/ey-core/requests/timeout_deployment.rb +27 -0
 - data/lib/ey-core/requests/upload_recipes_for_environment.rb +28 -0
 - data/lib/ey-core/version.rb +1 -1
 - data/spec/deployments_spec.rb +24 -0
 - data/spec/tokens_spec.rb +23 -1
 - metadata +228 -8
 
| 
         @@ -0,0 +1,92 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Ey::Core::Cli::Recipes < Ey::Core::Cli::Subcommand
         
     | 
| 
      
 2 
     | 
    
         
            +
              title "recipes"
         
     | 
| 
      
 3 
     | 
    
         
            +
              summary "Chef specific commands"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              Dir[File.dirname(__FILE__) + "/recipes/*.rb"].each { |file| load file }
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              Ey::Core::Cli::Recipes.descendants.each do |d|
         
     | 
| 
      
 8 
     | 
    
         
            +
                mount d
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              def run_chef(type, environment)
         
     | 
| 
      
 12 
     | 
    
         
            +
                request = environment.apply(type)
         
     | 
| 
      
 13 
     | 
    
         
            +
                puts "Started #{type} chef run".green
         
     | 
| 
      
 14 
     | 
    
         
            +
                request.wait_for { |r| r.ready? }
         
     | 
| 
      
 15 
     | 
    
         
            +
                if request.successful
         
     | 
| 
      
 16 
     | 
    
         
            +
                  puts "#{type.capitalize} chef run completed".green
         
     | 
| 
      
 17 
     | 
    
         
            +
                else
         
     | 
| 
      
 18 
     | 
    
         
            +
                  puts "#{type.capitalize} chef run failed".red
         
     | 
| 
      
 19 
     | 
    
         
            +
                  ap request
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              def gzip(tarfile)
         
     | 
| 
      
 24 
     | 
    
         
            +
                gz = StringIO.new("")
         
     | 
| 
      
 25 
     | 
    
         
            +
                z = Zlib::GzipWriter.new(gz)
         
     | 
| 
      
 26 
     | 
    
         
            +
                z.write tarfile.string
         
     | 
| 
      
 27 
     | 
    
         
            +
                z.close # this is necessary!
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                # z was closed to write the gzip footer, so
         
     | 
| 
      
 30 
     | 
    
         
            +
                # now we need a new StringIO
         
     | 
| 
      
 31 
     | 
    
         
            +
                StringIO.new gz.string
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              def archive_directory(path)
         
     | 
| 
      
 35 
     | 
    
         
            +
                tarfile = StringIO.new("")
         
     | 
| 
      
 36 
     | 
    
         
            +
                Gem::Package::TarWriter.new(tarfile) do |tar|
         
     | 
| 
      
 37 
     | 
    
         
            +
                  Dir[File.join(path, "**/*")].each do |file|
         
     | 
| 
      
 38 
     | 
    
         
            +
                    mode          = File.stat(file).mode
         
     | 
| 
      
 39 
     | 
    
         
            +
                    relative_file = "cookbooks/#{file.sub(/^#{Regexp::escape path}\/?/, '')}"
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    if File.directory?(file)
         
     | 
| 
      
 42 
     | 
    
         
            +
                      tar.mkdir relative_file, mode
         
     | 
| 
      
 43 
     | 
    
         
            +
                    else
         
     | 
| 
      
 44 
     | 
    
         
            +
                      tar.add_file relative_file, mode do |tf|
         
     | 
| 
      
 45 
     | 
    
         
            +
                        File.open(file, "rb") { |f| tf.write f.read }
         
     | 
| 
      
 46 
     | 
    
         
            +
                      end
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                tarfile.rewind
         
     | 
| 
      
 52 
     | 
    
         
            +
                gzip(tarfile)
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              def upload_recipes(environment, path="cookbooks/")
         
     | 
| 
      
 56 
     | 
    
         
            +
                recipes_path = Pathname.new(path)
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                if recipes_path.exist? && recipes_path.to_s.match(/\.(tgz|tar\.gz)/)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  environment.upload_recipes(recipes_path)
         
     | 
| 
      
 60 
     | 
    
         
            +
                elsif recipes_path.exist?
         
     | 
| 
      
 61 
     | 
    
         
            +
                  environment.upload_recipes(archive_directory(path))
         
     | 
| 
      
 62 
     | 
    
         
            +
                else
         
     | 
| 
      
 63 
     | 
    
         
            +
                  raise Ey::Core::Cli::RecipesNotFound, "Recipes file not found: #{recipes_path}"
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              def ungzip(tarfile)
         
     | 
| 
      
 68 
     | 
    
         
            +
                z = Zlib::GzipReader.new(tarfile)
         
     | 
| 
      
 69 
     | 
    
         
            +
                unzipped = StringIO.new(z.read)
         
     | 
| 
      
 70 
     | 
    
         
            +
                z.close
         
     | 
| 
      
 71 
     | 
    
         
            +
                unzipped
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
              def untar(io, destination)
         
     | 
| 
      
 76 
     | 
    
         
            +
                Gem::Package::TarReader.new io do |tar|
         
     | 
| 
      
 77 
     | 
    
         
            +
                  tar.each do |tarfile|
         
     | 
| 
      
 78 
     | 
    
         
            +
                    destination_file = File.join destination, tarfile.full_name
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                    if tarfile.directory?
         
     | 
| 
      
 81 
     | 
    
         
            +
                      FileUtils.mkdir_p destination_file
         
     | 
| 
      
 82 
     | 
    
         
            +
                    else
         
     | 
| 
      
 83 
     | 
    
         
            +
                      destination_directory = File.dirname(destination_file)
         
     | 
| 
      
 84 
     | 
    
         
            +
                      FileUtils.mkdir_p destination_directory unless File.directory?(destination_directory)
         
     | 
| 
      
 85 
     | 
    
         
            +
                      File.open destination_file, "wb" do |f|
         
     | 
| 
      
 86 
     | 
    
         
            +
                        f.print tarfile.read
         
     | 
| 
      
 87 
     | 
    
         
            +
                      end
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
              end
         
     | 
| 
      
 92 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Ey::Core::Cli::Recipes::Apply < Ey::Core::Cli::Recipes
         
     | 
| 
      
 2 
     | 
    
         
            +
              title "apply"
         
     | 
| 
      
 3 
     | 
    
         
            +
              summary "Apply changes to an environment"
         
     | 
| 
      
 4 
     | 
    
         
            +
              option :account, short: "c", long: "account", description: "Name or id of account", argument: "account"
         
     | 
| 
      
 5 
     | 
    
         
            +
              option :environment, short: "e", long: "environment", description: "Name or id of environment", argument: "environment"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              switch :main, short: "m", long: "main", description: "Apply main recipes only"
         
     | 
| 
      
 8 
     | 
    
         
            +
              switch :custom, long: "custom", description: "Apply custom recipes only"
         
     | 
| 
      
 9 
     | 
    
         
            +
              switch :quick, short: "q", long: "quick", description: "Quick chef run"
         
     | 
| 
      
 10 
     | 
    
         
            +
              switch :full, short: "f", long: "full", description: "Run main and custom chef"
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              def handle
         
     | 
| 
      
 13 
     | 
    
         
            +
                operator, environment = core_operator_and_environment_for(options)
         
     | 
| 
      
 14 
     | 
    
         
            +
                raise "Unable to find matching environment" unless environment
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                run_type = if switch_active?(:main)
         
     | 
| 
      
 17 
     | 
    
         
            +
                             "main"
         
     | 
| 
      
 18 
     | 
    
         
            +
                           elsif switch_active?(:custom)
         
     | 
| 
      
 19 
     | 
    
         
            +
                             "custom"
         
     | 
| 
      
 20 
     | 
    
         
            +
                           elsif switch_active?(:quick)
         
     | 
| 
      
 21 
     | 
    
         
            +
                             "quick"
         
     | 
| 
      
 22 
     | 
    
         
            +
                           elsif switch_active?(:full)
         
     | 
| 
      
 23 
     | 
    
         
            +
                             "main"
         
     | 
| 
      
 24 
     | 
    
         
            +
                           else
         
     | 
| 
      
 25 
     | 
    
         
            +
                             "main"
         
     | 
| 
      
 26 
     | 
    
         
            +
                           end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                run_chef(run_type, environment)
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                if switch_active?(:full)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  run_chef("custom", environment)
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Ey::Core::Cli::Recipes::Download < Ey::Core::Cli::Recipes
         
     | 
| 
      
 2 
     | 
    
         
            +
              title "download"
         
     | 
| 
      
 3 
     | 
    
         
            +
              summary "Download a copy of the custom chef recipes from this environment into the current directory"
         
     | 
| 
      
 4 
     | 
    
         
            +
              description <<-DESC
         
     | 
| 
      
 5 
     | 
    
         
            +
                The recipes will be unpacked into a directory called "cookbooks" in the
         
     | 
| 
      
 6 
     | 
    
         
            +
                current directory. This is the opposite of 'recipes upload'.
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                If the cookbooks directory already exists, an error will be raised.
         
     | 
| 
      
 9 
     | 
    
         
            +
              DESC
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              option :environment, short: "e", long: "environment", description: "Environment that will receive the recipes.", argument: "environment"
         
     | 
| 
      
 12 
     | 
    
         
            +
              option :account,     short: "c", long: "account",     description: "Name of the account in which the environment can be found.", argument: "account"
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              def handle
         
     | 
| 
      
 15 
     | 
    
         
            +
                if File.exist?("cookbooks")
         
     | 
| 
      
 16 
     | 
    
         
            +
                  raise Ey::Core::Clie::RecipesExist.new("Cannot download recipes, cookbooks directory already exists.")
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                operator, environment = core_operator_and_environment_for(options)
         
     | 
| 
      
 20 
     | 
    
         
            +
                puts "Downloading recipes".green
         
     | 
| 
      
 21 
     | 
    
         
            +
                recipes     = environment.download_recipes
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                puts "Extracting recipes to 'cookbooks/'".green
         
     | 
| 
      
 24 
     | 
    
         
            +
                untar(ungzip(recipes), './')
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Ey::Core::Cli::Recipes::Upload < Ey::Core::Cli::Recipes
         
     | 
| 
      
 2 
     | 
    
         
            +
              title "upload"
         
     | 
| 
      
 3 
     | 
    
         
            +
              summary "Upload custom recipes to an environment"
         
     | 
| 
      
 4 
     | 
    
         
            +
              option :environment, short: "e", long: "environment", description: "Environment that will receive the recipes.", argument: "environment"
         
     | 
| 
      
 5 
     | 
    
         
            +
              option :account,     short: "c", long: "account",     description: "Name of the account in which the environment can be found.", argument: "account"
         
     | 
| 
      
 6 
     | 
    
         
            +
              option :file,        short: "f", long: "file",        description: "Path to recipes", argument: "path"
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              switch :apply, short: "a", long: "apply", description: "Apply the recipes immediately after they are uploaded"
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              def handle
         
     | 
| 
      
 11 
     | 
    
         
            +
                operator, environment = core_operator_and_environment_for(options)
         
     | 
| 
      
 12 
     | 
    
         
            +
                path = option(:file) || "cookbooks/"
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                puts "Uploading custom recipes for #{environment.name}".green
         
     | 
| 
      
 15 
     | 
    
         
            +
                begin
         
     | 
| 
      
 16 
     | 
    
         
            +
                  upload_recipes(environment, path)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  puts "Uploading custom recipes complete".green
         
     | 
| 
      
 18 
     | 
    
         
            +
                rescue => e
         
     | 
| 
      
 19 
     | 
    
         
            +
                  abort "There was a problem uploading the recipes".red
         
     | 
| 
      
 20 
     | 
    
         
            +
                  puts e.inspect
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                if switch_active?(:apply)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  run_chef("custom", environment)
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,11 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Ey::Core::Cli::Scp < Ey::Core::Cli::Subcommand
         
     | 
| 
      
 2 
     | 
    
         
            +
              title "scp"
         
     | 
| 
      
 3 
     | 
    
         
            +
              summary "This command is deprecated"
         
     | 
| 
      
 4 
     | 
    
         
            +
              description <<-DESC
         
     | 
| 
      
 5 
     | 
    
         
            +
                The scp command has been deprecated.  We apologize for any inconvenience.
         
     | 
| 
      
 6 
     | 
    
         
            +
              DESC
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              def handle
         
     | 
| 
      
 9 
     | 
    
         
            +
                abort "This command is deprecated".red
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Ey::Core::Cli::Servers < Ey::Core::Cli::Subcommand
         
     | 
| 
      
 2 
     | 
    
         
            +
              title "servers"
         
     | 
| 
      
 3 
     | 
    
         
            +
              summary "List servers you have access to"
         
     | 
| 
      
 4 
     | 
    
         
            +
              option :account, short: 'c', long: 'account', description: 'Filter by account name or id', argument: 'Account'
         
     | 
| 
      
 5 
     | 
    
         
            +
              option :environment, short: "-e", long: "environment", description: "Filter by environment.", argument: "environment"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              def handle
         
     | 
| 
      
 8 
     | 
    
         
            +
                servers = if option(:account)
         
     | 
| 
      
 9 
     | 
    
         
            +
                            account = core_account_for(options)
         
     | 
| 
      
 10 
     | 
    
         
            +
                            core_client.servers.all(account: account)
         
     | 
| 
      
 11 
     | 
    
         
            +
                          elsif environment = option(:environment)
         
     | 
| 
      
 12 
     | 
    
         
            +
                            (core_client.environments.get(environment) || core_client.environments.first(name: environment)).servers.all
         
     | 
| 
      
 13 
     | 
    
         
            +
                          else
         
     | 
| 
      
 14 
     | 
    
         
            +
                            core_client.servers.all
         
     | 
| 
      
 15 
     | 
    
         
            +
                          end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                puts TablePrint::Printer.new(servers, [{id: {width: 10}}, :role, :provisioned_id]).table_print
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,94 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Ey::Core::Cli::Ssh < Ey::Core::Cli::Subcommand
         
     | 
| 
      
 2 
     | 
    
         
            +
              title "ssh"
         
     | 
| 
      
 3 
     | 
    
         
            +
              summary "Open an SSH session to the environment's application master"
         
     | 
| 
      
 4 
     | 
    
         
            +
              option :account, short: "c", long: "account", description: "Name or id of account", argument: "account"
         
     | 
| 
      
 5 
     | 
    
         
            +
              option :environment, short: "e", long: "environment", description: "Name or id of environment", argument: "environment"
         
     | 
| 
      
 6 
     | 
    
         
            +
              option :server, short: 's', long: "server", description: "Specific server to ssh into. Id or amazon id (i-12345)", argument: "server"
         
     | 
| 
      
 7 
     | 
    
         
            +
              option :utilities, long: "utilities", description: "Run command on the utility servers with the given names. Specify all to run the command on all utility servers.", argument: "'all,resque,redis,etc'"
         
     | 
| 
      
 8 
     | 
    
         
            +
              option :command, long: "command", description: "Command to run", argument: "'command with args'"
         
     | 
| 
      
 9 
     | 
    
         
            +
              option :shell, short: 's', long: "shell", description: "Run command in a shell other than bash", argument: "shell"
         
     | 
| 
      
 10 
     | 
    
         
            +
              option :bind_address, long: "bind_address", description: "When no command is specified, pass -L to ssh", argument: "bind address"
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              switch :all,         long: "all",         description: "Run command on all servers"
         
     | 
| 
      
 13 
     | 
    
         
            +
              switch :app_servers, long: "app_servers", description: "Run command on all application servers"
         
     | 
| 
      
 14 
     | 
    
         
            +
              switch :db_servers,  long: "db_servers",  description: "Run command on all database servers"
         
     | 
| 
      
 15 
     | 
    
         
            +
              switch :db_master,   long: "db_master",   description: "Run command on database master"
         
     | 
| 
      
 16 
     | 
    
         
            +
              switch :db_slaves,   long: "db_slaves",   description: "Run command on database slaves"
         
     | 
| 
      
 17 
     | 
    
         
            +
              switch :tty, short: 't', long: "tty",     description: "Allocated a tty for the command"
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              def handle
         
     | 
| 
      
 20 
     | 
    
         
            +
                operator, environment = core_operator_and_environment_for(options)
         
     | 
| 
      
 21 
     | 
    
         
            +
                abort "Unable to find matching environment".red unless environment
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                cmd      = option(:command)
         
     | 
| 
      
 24 
     | 
    
         
            +
                ssh_opts = []
         
     | 
| 
      
 25 
     | 
    
         
            +
                ssh_cmd  = ["ssh"]
         
     | 
| 
      
 26 
     | 
    
         
            +
                exits    = []
         
     | 
| 
      
 27 
     | 
    
         
            +
                user     = environment.username
         
     | 
| 
      
 28 
     | 
    
         
            +
                servers  = []
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                if option(:command)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  if shell = option(:shell)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    cmd = Escape.shell_command([shell,'-lc',cmd])
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  if switch_active?(:tty)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    ssh_opts << "-t"
         
     | 
| 
      
 39 
     | 
    
         
            +
                  elsif cmd.match(/sudo/)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    puts "sudo commands often need a tty to run correctly. Use -t option to spawn a tty.".yellow
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  if switch_active?(:all)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    servers += environment.servers.all.to_a
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  if switch_active?(:app_servers)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    servers += (environment.servers.all(role: "app_master") + environment.servers.all(role: "app") + environment.servers.all(role: "solo")).to_a
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  if switch_active?(:db_servers)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    servers += (environment.servers.all(role: "db_master") + environment.servers.all(role: "db_slave") + environment.servers.all(role: "solo")).to_a
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  if switch_active?(:db_master)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    servers += (environment.servers.all(role: "db_master") + environment.servers.all(role: "solo")).to_a
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  if utils = option(:utilities)
         
     | 
| 
      
 60 
     | 
    
         
            +
                    if utils == 'all'
         
     | 
| 
      
 61 
     | 
    
         
            +
                      servers += environment.servers.all(role: "util").to_a
         
     | 
| 
      
 62 
     | 
    
         
            +
                    else
         
     | 
| 
      
 63 
     | 
    
         
            +
                      servers += environment.servers.all(role: "util", name: utils).to_a
         
     | 
| 
      
 64 
     | 
    
         
            +
                    end
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
                else
         
     | 
| 
      
 67 
     | 
    
         
            +
                  if option(:bind_address)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    ssh_opts += ["-L", option(:bind_address)]
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  if option(:server)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    servers += [core_server_for(server: option[:server], operator: environment)]
         
     | 
| 
      
 73 
     | 
    
         
            +
                  else
         
     | 
| 
      
 74 
     | 
    
         
            +
                    servers += (environment.servers.all(role: "app_master") + environment.servers.all(role: "solo")).to_a
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                if servers.empty?
         
     | 
| 
      
 79 
     | 
    
         
            +
                  abort "Unable to find any matching servers. Aborting.".red
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                servers.each do |server|
         
     | 
| 
      
 83 
     | 
    
         
            +
                  host = server.public_hostname
         
     | 
| 
      
 84 
     | 
    
         
            +
                  name = server.name ? "#{server.role} (#{server.name})" : server.role
         
     | 
| 
      
 85 
     | 
    
         
            +
                  puts "\nConnecting to #{name} #{host}".green
         
     | 
| 
      
 86 
     | 
    
         
            +
                  sshcmd = Escape.shell_command((ssh_cmd + ["#{user}@#{host}"] + [cmd]).compact)
         
     | 
| 
      
 87 
     | 
    
         
            +
                  puts "Running command: #{sshcmd}".green
         
     | 
| 
      
 88 
     | 
    
         
            +
                  system sshcmd
         
     | 
| 
      
 89 
     | 
    
         
            +
                  exits << $?.exitstatus
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                exit exits.detect {|status| status != 0 } || 0
         
     | 
| 
      
 93 
     | 
    
         
            +
              end
         
     | 
| 
      
 94 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Ey::Core::Cli::Status < Ey::Core::Cli::Subcommand
         
     | 
| 
      
 2 
     | 
    
         
            +
              title "status"
         
     | 
| 
      
 3 
     | 
    
         
            +
              summary "Show the deployment status of the app"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              option :environment, short: "e", long: "environment", description: "Name or id of the environment to deploy to.", argument: "Environment"
         
     | 
| 
      
 6 
     | 
    
         
            +
              option :account,     short: 'c', long: 'account',     description: 'Name or ID of the account that the environment resides in.  If no account is specified, the app will deploy to the first environment that meets the criteria, in the accounts you have access to.', argument: 'Account name or id'
         
     | 
| 
      
 7 
     | 
    
         
            +
              option :app,         short: "a", long: "app",         description: "Application name or ID to deploy.  If :account is not specified, this will be the first app that matches the criteria in the accounts you have access to.", argument: "app"
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              description <<-DESC
         
     | 
| 
      
 10 
     | 
    
         
            +
                Show the current status of the most recent deployment of the specifed application and environment
         
     | 
| 
      
 11 
     | 
    
         
            +
              DESC
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              def handle
         
     | 
| 
      
 14 
     | 
    
         
            +
                operator, environment = core_operator_and_environment_for(self.options)
         
     | 
| 
      
 15 
     | 
    
         
            +
                app                   = core_application_for(self.options)
         
     | 
| 
      
 16 
     | 
    
         
            +
                deployments           = core_client.deployments.all(environment_id: environment.id, application_id: app.id)
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                ap deployments.first
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,114 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Ey::Core::Cli::Subcommand < Belafonte::App
         
     | 
| 
      
 2 
     | 
    
         
            +
              def self.descendants
         
     | 
| 
      
 3 
     | 
    
         
            +
                ObjectSpace.each_object(Class).select { |klass| klass < self }
         
     | 
| 
      
 4 
     | 
    
         
            +
              end
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_accessor :core_file
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def core_file
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @core_file ||= File.expand_path("~/.ey-core")
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def eyrc
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @eyrc ||= File.expand_path("~/.eyrc")
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def unauthenticated_core_client
         
     | 
| 
      
 19 
     | 
    
         
            +
                @unauthenticated_core_client ||= Ey::Core::Client.new(token: nil, url: core_url)
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              def core_client
         
     | 
| 
      
 23 
     | 
    
         
            +
                @core_client ||= Ey::Core::Client.new(url: core_url, config_file: self.class.core_file)
         
     | 
| 
      
 24 
     | 
    
         
            +
              rescue RuntimeError => e
         
     | 
| 
      
 25 
     | 
    
         
            +
                if legacy_token = e.message.match(/missing token/i) && eyrc_yaml["api_token"]
         
     | 
| 
      
 26 
     | 
    
         
            +
                  puts "Found legacy .eyrc token.  Migrating to core file".green
         
     | 
| 
      
 27 
     | 
    
         
            +
                  write_core_yaml(legacy_token)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  retry
         
     | 
| 
      
 29 
     | 
    
         
            +
                elsif e.message.match(/missing token/i)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  abort "Missing credentials: Run 'ey login' to retrieve your Engine Yard Cloud API token.".yellow
         
     | 
| 
      
 31 
     | 
    
         
            +
                else
         
     | 
| 
      
 32 
     | 
    
         
            +
                  raise e
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              def core_url
         
     | 
| 
      
 37 
     | 
    
         
            +
                env_url = ENV["CORE_URL"] || ENV["CLOUD_URL"]
         
     | 
| 
      
 38 
     | 
    
         
            +
                (env_url && File.join(env_url, '/')) || "https://api.engineyard.com/"
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              def current_accounts
         
     | 
| 
      
 42 
     | 
    
         
            +
                core_client.users.current.accounts
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              def longest_length_by_name(collection)
         
     | 
| 
      
 46 
     | 
    
         
            +
                collection.map(&:name).group_by(&:size).max.last.length
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              def write_core_yaml(token=nil)
         
     | 
| 
      
 50 
     | 
    
         
            +
                core_yaml[core_url] = token if token
         
     | 
| 
      
 51 
     | 
    
         
            +
                File.open(self.class.core_file, "w") { |f| f.puts core_yaml.to_yaml }
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              def eyrc_yaml
         
     | 
| 
      
 55 
     | 
    
         
            +
                @eyrc_yaml ||= YAML.load_file(self.class.eyrc) || {}
         
     | 
| 
      
 56 
     | 
    
         
            +
              rescue Errno::ENOENT => e # we don't really care if this doesn't exist
         
     | 
| 
      
 57 
     | 
    
         
            +
                {}
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              def core_yaml
         
     | 
| 
      
 61 
     | 
    
         
            +
                @core_yaml ||= YAML.load_file(self.class.core_file) || {}
         
     | 
| 
      
 62 
     | 
    
         
            +
              rescue Errno::ENOENT => e
         
     | 
| 
      
 63 
     | 
    
         
            +
                puts "Creating #{self.class.core_file}".yellow
         
     | 
| 
      
 64 
     | 
    
         
            +
                FileUtils.touch(self.class.core_file)
         
     | 
| 
      
 65 
     | 
    
         
            +
                retry
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
              def core_account_for(options={})
         
     | 
| 
      
 69 
     | 
    
         
            +
                @core_account ||= core_client.accounts.get(options[:account])
         
     | 
| 
      
 70 
     | 
    
         
            +
                @core_account ||= core_client.users.current.accounts.first(name: options[:account])
         
     | 
| 
      
 71 
     | 
    
         
            +
              end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
              def operator(options)
         
     | 
| 
      
 74 
     | 
    
         
            +
                options[:account] ? core_account_for(options) : core_client
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
              def core_operator_and_environment_for(options={})
         
     | 
| 
      
 78 
     | 
    
         
            +
                operator = operator(options)
         
     | 
| 
      
 79 
     | 
    
         
            +
                environment = operator.environments.get(options[:environment]) || operator.environments.first(name: options[:environment])
         
     | 
| 
      
 80 
     | 
    
         
            +
                [operator, environment]
         
     | 
| 
      
 81 
     | 
    
         
            +
              end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
              def core_environment_for(options={})
         
     | 
| 
      
 84 
     | 
    
         
            +
                core_client.environments.get(options[:environment]) || core_client.environments.first(name: options[:environment])
         
     | 
| 
      
 85 
     | 
    
         
            +
              end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
              def core_server_for(options={})
         
     | 
| 
      
 88 
     | 
    
         
            +
                operator = options.fetch(:operator, core_client)
         
     | 
| 
      
 89 
     | 
    
         
            +
                operator.servers.get(options[:server]) || operator.servers.first(provisioned_id: options[:server])
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
              def core_application_for(options={})
         
     | 
| 
      
 93 
     | 
    
         
            +
                return nil unless options[:app]
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                app = begin
         
     | 
| 
      
 96 
     | 
    
         
            +
                        Integer(options[:app])
         
     | 
| 
      
 97 
     | 
    
         
            +
                      rescue
         
     | 
| 
      
 98 
     | 
    
         
            +
                        options[:app]
         
     | 
| 
      
 99 
     | 
    
         
            +
                      end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                actor = options[:environment].is_a?(Ey::Core::Client::Environment) ? options[:environment].account : operator(options)
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                if app.is_a?(Integer)
         
     | 
| 
      
 104 
     | 
    
         
            +
                  actor.applications.get(app)
         
     | 
| 
      
 105 
     | 
    
         
            +
                else
         
     | 
| 
      
 106 
     | 
    
         
            +
                  applications = actor.applications.all(name: app)
         
     | 
| 
      
 107 
     | 
    
         
            +
                  if applications.count == 1
         
     | 
| 
      
 108 
     | 
    
         
            +
                    applications.first
         
     | 
| 
      
 109 
     | 
    
         
            +
                  else
         
     | 
| 
      
 110 
     | 
    
         
            +
                    raise Ey::Core::Cli::AmbiguousSearch.new("Found multiple applications that matched that search.  Please be more specific by specifying the account, environment, and application name.")
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
                end
         
     | 
| 
      
 113 
     | 
    
         
            +
              end
         
     | 
| 
      
 114 
     | 
    
         
            +
            end
         
     |