ey-core 3.1.2 → 3.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.ruby-version +1 -1
  2. data/.travis.yml +1 -0
  3. data/Gemfile +0 -2
  4. data/examples/add_instance.rb +74 -0
  5. data/examples/boot_env.rb +60 -0
  6. data/examples/stop_env.rb +51 -0
  7. data/examples/terminate_instance.rb +58 -0
  8. data/lib/ey-core/cli/accounts.rb +14 -6
  9. data/lib/ey-core/cli/applications.rb +32 -12
  10. data/lib/ey-core/cli/console.rb +24 -10
  11. data/lib/ey-core/cli/current_user.rb +13 -5
  12. data/lib/ey-core/cli/deploy.rb +110 -52
  13. data/lib/ey-core/cli/environments.rb +34 -12
  14. data/lib/ey-core/cli/errors.rb +10 -6
  15. data/lib/ey-core/cli/help.rb +30 -0
  16. data/lib/ey-core/cli/helpers/archive.rb +70 -0
  17. data/lib/ey-core/cli/helpers/chef.rb +35 -0
  18. data/lib/ey-core/cli/helpers/core.rb +195 -0
  19. data/lib/ey-core/cli/helpers/deprecated.rb +39 -0
  20. data/lib/ey-core/cli/helpers/log_streaming.rb +41 -0
  21. data/lib/ey-core/cli/helpers/stream_printer.rb +42 -0
  22. data/lib/ey-core/cli/init.rb +11 -8
  23. data/lib/ey-core/cli/login.rb +33 -21
  24. data/lib/ey-core/cli/logout.rb +18 -10
  25. data/lib/ey-core/cli/logs.rb +57 -35
  26. data/lib/ey-core/cli/main.rb +52 -15
  27. data/lib/ey-core/cli/recipes.rb +5 -87
  28. data/lib/ey-core/cli/recipes/apply.rb +83 -43
  29. data/lib/ey-core/cli/recipes/download.rb +48 -22
  30. data/lib/ey-core/cli/recipes/main.rb +21 -0
  31. data/lib/ey-core/cli/recipes/upload.rb +56 -23
  32. data/lib/ey-core/cli/scp.rb +11 -8
  33. data/lib/ey-core/cli/servers.rb +37 -15
  34. data/lib/ey-core/cli/ssh.rb +127 -70
  35. data/lib/ey-core/cli/status.rb +54 -14
  36. data/lib/ey-core/cli/subcommand.rb +47 -108
  37. data/lib/ey-core/cli/timeout_deploy.rb +56 -26
  38. data/lib/ey-core/cli/version.rb +13 -5
  39. data/lib/ey-core/cli/web.rb +7 -7
  40. data/lib/ey-core/cli/web/disable.rb +46 -20
  41. data/lib/ey-core/cli/web/enable.rb +40 -17
  42. data/lib/ey-core/cli/web/main.rb +21 -0
  43. data/lib/ey-core/cli/web/restart.rb +34 -15
  44. data/lib/ey-core/cli/whoami.rb +11 -3
  45. data/lib/ey-core/mock/searching.rb +4 -0
  46. data/lib/ey-core/model.rb +5 -0
  47. data/lib/ey-core/models/deployment.rb +7 -0
  48. data/lib/ey-core/models/environment.rb +5 -0
  49. data/lib/ey-core/models/request.rb +2 -0
  50. data/lib/ey-core/models/user.rb +2 -0
  51. data/lib/ey-core/requests/get_servers.rb +1 -1
  52. data/lib/ey-core/response.rb +4 -0
  53. data/lib/ey-core/subscribable.rb +3 -3
  54. data/lib/ey-core/version.rb +1 -1
  55. data/spec/ey-core/cli/accounts_spec.rb +20 -0
  56. data/spec/ey-core/cli/recipes/apply_spec.rb +4 -17
  57. data/spec/ey-core/cli/recipes/download_spec.rb +93 -0
  58. data/spec/ey-core/cli/recipes/upload_spec.rb +80 -0
  59. data/spec/servers_spec.rb +15 -0
  60. data/spec/spec_helper.rb +7 -0
  61. data/spec/support/cli_helpers.rb +38 -2
  62. metadata +116 -53
  63. checksums.yaml +0 -7
@@ -0,0 +1,42 @@
1
+ module Ey
2
+ module Core
3
+ module Cli
4
+ module Helpers
5
+ module StreamPrinter
6
+
7
+ def stream_print(opts)
8
+ yield Printer.new(opts)
9
+ end
10
+
11
+ class Printer
12
+ def initialize(rows = {})
13
+ @rows = rows
14
+ end
15
+ def print(*vals)
16
+ unless @header_printed
17
+ header = []
18
+ separator = []
19
+ @rows.each do |k,v|
20
+ header << format(k, v)
21
+ separator << '-' * v
22
+ end
23
+ puts header.join("| ")
24
+ puts separator.join("|-")
25
+ @header_printed = true
26
+ end
27
+ line = []
28
+ vals.each_with_index do |v,index|
29
+ line << format(v, @rows.values[index])
30
+ end
31
+ puts line.join("| ")
32
+ end
33
+ def format(value, width)
34
+ TablePrint::FixedWidthFormatter.new(width).format(value)
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,11 +1,14 @@
1
- class Ey::Core::Cli::Init < Ey::Core::Cli::Subcommand
2
- title "init"
3
- summary "Deprecated"
4
- description <<-DESC
5
- The init command has been deprecated. We apologize for any inconvenience.
6
- DESC
1
+ require 'ey-core/cli/subcommand'
2
+ require 'ey-core/cli/helpers/deprecated'
7
3
 
8
- def handle
9
- abort "This command is deprecated".red
4
+ module Ey
5
+ module Core
6
+ module Cli
7
+ class Init < Subcommand
8
+ include Helpers::Deprecated
9
+
10
+ deprecate('init')
11
+ end
12
+ end
10
13
  end
11
14
  end
@@ -1,26 +1,38 @@
1
- class Ey::Core::Cli::Login < Ey::Core::Cli::Subcommand
2
- title "login"
3
- summary "Retrieve API token from Engine Yard Cloud"
1
+ require 'ey-core/cli/subcommand'
4
2
 
5
- def handle
6
- email = ENV["EMAIL"] || ask("Email: ")
7
- password = ENV["PASSWORD"] || ask("Password: ") { |q| q.echo = false }
3
+ module Ey
4
+ module Core
5
+ module Cli
6
+ class Login < Subcommand
7
+ title "login"
8
+ summary "Retrieve API token from Engine Yard Cloud"
8
9
 
9
- token = unauthenticated_core_client.get_api_token(email, password).body["api_token"]
10
+ def handle
11
+ email = ENV["EMAIL"] || ask("Email: ")
12
+ password = ENV["PASSWORD"] || ask("Password: ") { |q| q.echo = false }
10
13
 
11
- existing_token = core_yaml[core_url]
12
- write_token = if existing_token && existing_token != token
13
- puts "New token does not match existing token. Overwriting".yellow
14
- true
15
- elsif existing_token == token
16
- puts "Token already exists".green
17
- false
18
- else
19
- puts "Writing token".green
20
- true
21
- end
22
- write_core_yaml(token) if write_token
23
- rescue Ey::Core::Response::Unauthorized
24
- abort "Invalid email or password".yellow
14
+ token = unauthenticated_core_client.
15
+ get_api_token(email, password).
16
+ body["api_token"]
17
+
18
+ existing_token = core_yaml[core_url]
19
+ write_token= if existing_token && existing_token != token
20
+ puts "New token does not match existing token. Overwriting".yellow
21
+ true
22
+ elsif existing_token == token
23
+ puts "Token already exists".green
24
+ false
25
+ else
26
+ puts "Writing token".green
27
+ true
28
+ end
29
+
30
+ write_core_yaml(token) if write_token
31
+
32
+ rescue Ey::Core::Response::Unauthorized
33
+ abort "Invalid email or password".yellow
34
+ end
35
+ end
36
+ end
25
37
  end
26
38
  end
@@ -1,14 +1,22 @@
1
- class Ey::Core::Cli::Logout < Ey::Core::Cli::Subcommand
2
- title "logout"
3
- summary "Remove your Engine Yard API token"
1
+ require 'ey-core/cli/subcommand'
4
2
 
5
- def handle
6
- if core_yaml[core_url]
7
- core_yaml.delete(core_url)
8
- write_core_yaml
9
- puts "Successfully removed API token from credentials file".green
10
- else
11
- puts "No API token found".yellow
3
+ module Ey
4
+ module Core
5
+ module Cli
6
+ class Logout < Subcommand
7
+ title "logout"
8
+ summary "Remove your Engine Yard API token"
9
+
10
+ def handle
11
+ if core_yaml[core_url]
12
+ core_yaml.delete(core_url)
13
+ write_core_yaml
14
+ puts "Successfully removed API token from credentials file".green
15
+ else
16
+ puts "No API token found".yellow
17
+ end
18
+ end
19
+ end
12
20
  end
13
21
  end
14
22
  end
@@ -1,39 +1,61 @@
1
- class Ey::Core::Cli::Logs < Ey::Core::Cli::Subcommand
2
- title "logs"
3
- summary "Retrieve the latest logs for an environment"
4
- description <<-DESC
5
- Displays Engine Yard configuration logs for all servers in the environment. If
6
- recipes were uploaded to the environment & run, their logs will also be
7
- displayed beneath the main configuration logs.
8
- DESC
9
-
10
- option :environment, short: "e", long: "environment", description: "Name or id of the environment to deploy to.", argument: "Environment"
11
- 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'
12
- option :server, short: 's', long: 'server', description: "Only retrieve logs for the specified server", argument: "id or amazon_id"
13
-
14
- def handle
15
- operator, environment = core_operator_and_environment_for(options)
16
- abort "Unable to find matching environment".red unless environment
17
-
18
- servers = if option(:server)
19
- [environment.servers.get(option(:server))] || environment.servers.all(provisioned_id: option(:server))
20
- else
21
- environment.servers.all
22
- end
23
-
24
- abort "No servers found".red if servers.empty?
25
-
26
- servers.each do |server|
27
- name = server.name ? "#{server.name} (#{server.role})" : server.role
28
-
29
- if log = server.latest_main_log
30
- puts "Main logs for #{name}:".green
31
- puts log.contents
32
- end
1
+ require 'ey-core/cli/subcommand'
2
+
3
+ module Ey
4
+ module Core
5
+ module Cli
6
+ class Logs < Subcommand
7
+ title "logs"
8
+ summary "Retrieve the latest logs for an environment"
9
+ description <<-DESC
10
+ Displays Engine Yard configuration logs for all servers in the environment. If
11
+ recipes were uploaded to the environment & run, their logs will also be
12
+ displayed beneath the main configuration logs.
13
+ DESC
14
+
15
+ option :environment,
16
+ short: "e",
17
+ long: "environment",
18
+ description: "Name or id of the environment to deploy to.",
19
+ argument: "Environment"
20
+
21
+ option :account,
22
+ short: 'c',
23
+ long: 'account',
24
+ 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.',
25
+ argument: 'Account name or id'
26
+
27
+ option :server,
28
+ short: 's',
29
+ long: 'server',
30
+ description: "Only retrieve logs for the specified server",
31
+ argument: "id or amazon_id"
32
+
33
+ def handle
34
+ operator, environment = core_operator_and_environment_for(options)
35
+ abort "Unable to find matching environment".red unless environment
36
+
37
+ servers = if option(:server)
38
+ [environment.servers.get(option(:server))] || environment.servers.all(provisioned_id: option(:server))
39
+ else
40
+ environment.servers.all
41
+ end
42
+
43
+ abort "No servers found".red if servers.empty?
44
+
45
+ servers.each do |server|
46
+ name = server.name ? "#{server.name} (#{server.role})" : server.role
47
+
48
+ if log = server.latest_main_log
49
+ puts "Main logs for #{name}:".green
50
+ puts log.contents
51
+ end
33
52
 
34
- if log = server.latest_custom_log
35
- puts "Custom logs for #{name}:".green
36
- puts log.contents
53
+ if log = server.latest_custom_log
54
+ puts "Custom logs for #{name}:".green
55
+ puts log.contents
56
+ end
57
+ end
58
+ end
37
59
  end
38
60
  end
39
61
  end
@@ -1,28 +1,65 @@
1
- require 'optparse'
2
- require 'ostruct'
3
- require 'ey-core'
1
+ #require 'optparse'
2
+ #require 'ostruct'
3
+ #require 'ey-core'
4
4
  require 'ey-core/cli'
5
5
  require 'awesome_print'
6
- require 'pry'
7
6
  require 'belafonte'
8
- require 'table_print'
9
7
  require 'rubygems/package'
10
8
  require 'escape'
11
9
  require 'highline/import'
12
10
 
13
- Cistern.formatter = Cistern::Formatter::AwesomePrint
11
+ require 'ey-core/cli/accounts'
12
+ require 'ey-core/cli/applications'
13
+ require 'ey-core/cli/console'
14
+ require 'ey-core/cli/current_user'
15
+ require 'ey-core/cli/deploy'
16
+ require 'ey-core/cli/environments'
17
+ require 'ey-core/cli/help'
18
+ require 'ey-core/cli/init'
19
+ require 'ey-core/cli/login'
20
+ require 'ey-core/cli/logout'
21
+ require 'ey-core/cli/logs'
22
+ require 'ey-core/cli/recipes'
23
+ require 'ey-core/cli/scp'
24
+ require 'ey-core/cli/servers'
25
+ require 'ey-core/cli/ssh'
26
+ require 'ey-core/cli/status'
27
+ require 'ey-core/cli/timeout_deploy'
28
+ require 'ey-core/cli/version'
29
+ require 'ey-core/cli/web'
30
+ require 'ey-core/cli/whoami'
14
31
 
32
+ Cistern.formatter = Cistern::Formatter::AwesomePrint
15
33
 
16
- class Ey::Core::Cli::Main < Belafonte::App
17
- title "Engineyard CLI"
18
- summary "Successor to the engineyard gem"
19
34
 
20
- require_relative "subcommand"
21
- Dir[File.dirname(__FILE__) + '/*.rb'].
22
- reject {|file| file =~ /.*\/main\.rb$/}.
23
- each {|file| load file }
35
+ module Ey
36
+ module Core
37
+ module Cli
38
+ class Main < Belafonte::App
39
+ title "Engineyard CLI"
40
+ summary "Successor to the engineyard gem"
24
41
 
25
- Ey::Core::Cli::Subcommand.descendants.each do |d|
26
- mount d
42
+ mount Accounts
43
+ mount Applications
44
+ mount Console
45
+ mount CurrentUser
46
+ mount Deploy
47
+ mount Environments
48
+ mount Help
49
+ mount Init
50
+ mount Login
51
+ mount Logout
52
+ mount Logs
53
+ mount Recipes::Main
54
+ mount Scp
55
+ mount Servers
56
+ mount Ssh
57
+ mount Status
58
+ mount TimeoutDeploy
59
+ mount Version
60
+ mount Web::Main
61
+ mount Whoami
62
+ end
63
+ end
27
64
  end
28
65
  end
@@ -1,91 +1,9 @@
1
- class Ey::Core::Cli::Recipes < Ey::Core::Cli::Subcommand
2
- title "recipes"
3
- summary "Chef specific commands"
1
+ require 'ey-core/cli/recipes/main'
4
2
 
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
3
+ module Ey
4
+ module Core
5
+ module Cli
6
+ module Recipes
89
7
  end
90
8
  end
91
9
  end
@@ -1,56 +1,96 @@
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"
1
+ require 'ey-core/cli/subcommand'
2
+ require 'ey-core/cli/helpers/chef'
6
3
 
7
- switch :main, short: "m", long: "main", description: "Apply main recipes only"
8
- switch :custom, short: "u", 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"
4
+ module Ey
5
+ module Core
6
+ module Cli
7
+ module Recipes
8
+ class Apply < Subcommand
9
+ include Helpers::Chef
11
10
 
12
- def handle
13
- validate_run_type_flags
11
+ title "apply"
12
+ summary "Apply changes to an environment"
14
13
 
15
- operator, environment = core_operator_and_environment_for(options)
16
- raise "Unable to find matching environment" unless environment
14
+ option :account,
15
+ short: "c",
16
+ long: "account",
17
+ description: "Name or id of account",
18
+ argument: "account"
17
19
 
18
- run_chef(run_type, environment)
20
+ option :environment,
21
+ short: "e",
22
+ long: "environment",
23
+ description: "Name or id of environment",
24
+ argument: "environment"
19
25
 
20
- if switch_active?(:full)
21
- run_chef("custom", environment)
22
- end
23
- end
26
+ switch :main,
27
+ short: "m",
28
+ long: "main",
29
+ description: "Apply main recipes only"
24
30
 
25
- private
26
- def validate_run_type_flags
27
- if active_run_type_flags.length > 1
28
- kernel.abort(
29
- 'Only one of --main, --custom, --quick, and --full may be specified.'
30
- )
31
- end
32
- end
31
+ switch :custom,
32
+ short: "u",
33
+ long: "custom",
34
+ description: "Apply custom recipes only"
33
35
 
34
- def run_type
35
- secondary_run_types[active_run_type] || default_run_type
36
- end
36
+ switch :quick,
37
+ short: "q",
38
+ long: "quick",
39
+ description: "Quick chef run"
37
40
 
38
- def active_run_type
39
- active_run_type_flags.first
40
- end
41
+ switch :full,
42
+ short: "f",
43
+ long: "full",
44
+ description: "Run main and custom chef"
41
45
 
42
- def active_run_type_flags
43
- [:main, :custom, :quick, :full].select {|switch| switch_active?(switch)}
44
- end
46
+ def handle
47
+ validate_run_type_flags
45
48
 
46
- def secondary_run_types
47
- {
48
- custom: 'custom',
49
- quick: 'quick'
50
- }
51
- end
49
+ operator, environment = core_operator_and_environment_for(options)
50
+ raise "Unable to find matching environment" unless environment
52
51
 
53
- def default_run_type
54
- 'main'
52
+ run_chef(run_type, environment)
53
+
54
+ if switch_active?(:full)
55
+ run_chef("custom", environment)
56
+ end
57
+ end
58
+
59
+ private
60
+ def validate_run_type_flags
61
+ if active_run_type_flags.length > 1
62
+ kernel.abort(
63
+ 'Only one of --main, --custom, --quick, and --full may be specified.'
64
+ )
65
+ end
66
+ end
67
+
68
+ def run_type
69
+ secondary_run_types[active_run_type] || default_run_type
70
+ end
71
+
72
+ def active_run_type
73
+ active_run_type_flags.first
74
+ end
75
+
76
+ def active_run_type_flags
77
+ [:main, :custom, :quick, :full].select {|switch|
78
+ switch_active?(switch)
79
+ }
80
+ end
81
+
82
+ def secondary_run_types
83
+ {
84
+ custom: 'custom',
85
+ quick: 'quick'
86
+ }
87
+ end
88
+
89
+ def default_run_type
90
+ 'main'
91
+ end
92
+ end
93
+ end
94
+ end
55
95
  end
56
96
  end