ey-core 3.0.5 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -7
  3. data/bin/ey-core +1 -1
  4. data/ey-core.gemspec +15 -1
  5. data/lib/ey-core/cli.rb +12 -114
  6. data/lib/ey-core/cli/accounts.rb +9 -0
  7. data/lib/ey-core/cli/applications.rb +16 -0
  8. data/lib/ey-core/cli/console.rb +14 -0
  9. data/lib/ey-core/cli/current_user.rb +8 -0
  10. data/lib/ey-core/cli/deploy.rb +65 -0
  11. data/lib/ey-core/cli/environments.rb +17 -0
  12. data/lib/ey-core/cli/errors.rb +7 -0
  13. data/lib/ey-core/cli/init.rb +11 -0
  14. data/lib/ey-core/cli/login.rb +26 -0
  15. data/lib/ey-core/cli/logout.rb +14 -0
  16. data/lib/ey-core/cli/logs.rb +40 -0
  17. data/lib/ey-core/cli/recipes.rb +92 -0
  18. data/lib/ey-core/cli/recipes/apply.rb +34 -0
  19. data/lib/ey-core/cli/recipes/download.rb +26 -0
  20. data/lib/ey-core/cli/recipes/upload.rb +27 -0
  21. data/lib/ey-core/cli/scp.rb +11 -0
  22. data/lib/ey-core/cli/servers.rb +19 -0
  23. data/lib/ey-core/cli/ssh.rb +94 -0
  24. data/lib/ey-core/cli/status.rb +20 -0
  25. data/lib/ey-core/cli/subcommand.rb +114 -0
  26. data/lib/ey-core/cli/timeout_deploy.rb +28 -0
  27. data/lib/ey-core/cli/version.rb +8 -0
  28. data/lib/ey-core/cli/web.rb +10 -0
  29. data/lib/ey-core/cli/web/disable.rb +23 -0
  30. data/lib/ey-core/cli/web/enable.rb +23 -0
  31. data/lib/ey-core/cli/web/restart.rb +23 -0
  32. data/lib/ey-core/cli/whoami.rb +4 -0
  33. data/lib/ey-core/client.rb +9 -0
  34. data/lib/ey-core/client/mock.rb +1 -0
  35. data/lib/ey-core/client/real.rb +4 -4
  36. data/lib/ey-core/collections/deployments.rb +8 -0
  37. data/lib/ey-core/models/account.rb +1 -0
  38. data/lib/ey-core/models/deployment.rb +23 -0
  39. data/lib/ey-core/models/environment.rb +37 -0
  40. data/lib/ey-core/requests/change_environment_maintenance.rb +38 -0
  41. data/lib/ey-core/requests/create_environment.rb +3 -0
  42. data/lib/ey-core/requests/deploy_environment_application.rb +17 -0
  43. data/lib/ey-core/requests/get_deployment.rb +19 -0
  44. data/lib/ey-core/requests/get_deployments.rb +29 -0
  45. data/lib/ey-core/requests/get_token_by_login.rb +30 -0
  46. data/lib/ey-core/requests/restart_environment_app_servers.rb +38 -0
  47. data/lib/ey-core/requests/timeout_deployment.rb +27 -0
  48. data/lib/ey-core/requests/upload_recipes_for_environment.rb +28 -0
  49. data/lib/ey-core/version.rb +1 -1
  50. data/spec/deployments_spec.rb +24 -0
  51. data/spec/tokens_spec.rb +23 -1
  52. metadata +228 -8
@@ -0,0 +1,28 @@
1
+ class Ey::Core::Cli::TimeoutDeploy < Ey::Core::Cli::Subcommand
2
+ title "timeout-deploy"
3
+ summary "Fail a stuck unfinished deployment"
4
+ description <<-DESC
5
+ NOTICE: Timing out a deploy does not stop currently running deploy
6
+ processes.
7
+
8
+ The latest running deployment will be marked as failed, allowing a
9
+ new deployment to be run. It is possible to mark a potentially successful
10
+ deployment as failed. Only run this when a deployment is known to be
11
+ wrongly unfinished/stuck and when further deployments are blocked.
12
+ DESC
13
+
14
+ option :environment, short: "e", long: "environment", description: "Name or id of the environment to deploy to.", argument: "Environment"
15
+ 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'
16
+ 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"
17
+ option :message, short: "m", long: "message", description: "Custom message for why the deploy is timed out", argument: "message"
18
+
19
+ def handle
20
+ operator, environment = core_operator_and_environment_for(self.options)
21
+ app = core_application_for(self.options)
22
+ deployment = core_client.deployments.first(environment_id: environment.id, application_id: app.id)
23
+
24
+ puts "Timing out the most recent deployment (deploy started at: #{deployment.started_at})".green
25
+ deployment.timeout(option(:message))
26
+ ap deployment
27
+ end
28
+ end
@@ -0,0 +1,8 @@
1
+ class Ey::Core::Cli::Version < Ey::Core::Cli::Subcommand
2
+ title "version"
3
+ summary "Print the version of the gem"
4
+
5
+ def handle
6
+ puts Ey::Core::VERSION
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ class Ey::Core::Cli::Web < Ey::Core::Cli::Subcommand
2
+ title "web"
3
+ summary "Web related commands"
4
+
5
+ Dir[File.dirname(__FILE__) + "/web/*.rb"].each { |file| load file }
6
+
7
+ Ey::Core::Cli::Web.descendants.each do |d|
8
+ mount d
9
+ end
10
+ end
@@ -0,0 +1,23 @@
1
+ class Ey::Core::Cli::Web::Disable < Ey::Core::Cli::Web
2
+ title "disable"
3
+ summary "Put up the maintenance page for this application in the given environment."
4
+
5
+ option :app, short: "a", long: "app", description: "Name or id of the application whose maintenance page will be put up", argument: "app"
6
+ option :environment, short: "e", long: "environment", description: "Name or id of the environment to deploy to.", argument: "Environment"
7
+ option :account, short: 'c', long: 'account', description: 'Name or ID of the account that the environment resides in.', argument: 'Account name or id'
8
+
9
+ def handle
10
+ operator, environment = core_operator_and_environment_for(self.options)
11
+ application = core_application_for(self.options)
12
+
13
+ puts "Enabling maintenance page for #{application.name} on #{environment.name}".green
14
+ request = environment.maintenance(application, "enable")
15
+ request.wait_for { |r| r.ready? }
16
+ if request.successful
17
+ puts "Successfully put up maintenance page".green
18
+ else
19
+ puts "Enabling maintenance mode was not successful".red
20
+ ap request
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ class Ey::Core::Cli::Web::Enable < Ey::Core::Cli::Web
2
+ title "enable"
3
+ summary "Remove the maintenance page for this application in the given environment."
4
+
5
+ option :app, short: "a", long: "app", description: "Name or id of the application whose maintenance page will be removed", argument: "app"
6
+ option :environment, short: "e", long: "environment", description: "Name or id of the environment to deploy to.", argument: "Environment"
7
+ option :account, short: 'c', long: 'account', description: 'Name or ID of the account that the environment resides in.', argument: 'account'
8
+
9
+ def handle
10
+ operator, environment = core_operator_and_environment_for(self.options)
11
+ application = core_application_for(self.options)
12
+
13
+ puts "Disabling maintenance for #{application.name} on #{environment.name}".green
14
+ request = environment.maintenance(application, "disable")
15
+ request.wait_for { |r| r.ready? }
16
+ if request.successful
17
+ puts "Successfully disabled maintenance page".green
18
+ else
19
+ puts "Disabling maintenance mode was not successful".red
20
+ ap request
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ class Ey::Core::Cli::Web::Restart < Ey::Core::Cli::Web
2
+ title "restart"
3
+ summary "Restart all application servers in an environment"
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.", argument: "account"
7
+
8
+ def handle
9
+ operator, environment = core_operator_and_environment_for(options)
10
+
11
+ puts "Restarting application servers in #{environment.name}".green
12
+
13
+ request = environment.restart_app_servers
14
+ request.wait_for { |r| r.ready? }
15
+
16
+ if request.successful
17
+ puts "Successfully restarted application servers".green
18
+ else
19
+ puts "Restarting application servers has failed".red
20
+ ap request
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,4 @@
1
+ class Ey::Core::Cli::Whoami < Ey::Core::Cli::CurrentUser
2
+ title "whoami"
3
+ summary "Print the current user information (alias for current_user)"
4
+ end
@@ -25,6 +25,7 @@ class Ey::Core::Client < Cistern::Service
25
25
  collection :database_server_usages
26
26
  collection :database_servers
27
27
  collection :database_services
28
+ collection :deployments
28
29
  collection :environment_plan_usages
29
30
  collection :environments
30
31
  collection :features
@@ -81,6 +82,7 @@ class Ey::Core::Client < Cistern::Service
81
82
  model :database_server_snapshot
82
83
  model :database_server_usage
83
84
  model :database_service
85
+ model :deployment
84
86
  model :environment
85
87
  model :environment_plan_usage
86
88
  model :feature
@@ -124,6 +126,7 @@ class Ey::Core::Client < Cistern::Service
124
126
  request :boot_environment
125
127
  request :bootstrap_logical_database
126
128
  request :cancel_account
129
+ request :change_environment_maintenance
127
130
  request :create_account
128
131
  request :create_addon
129
132
  request :create_address
@@ -219,6 +222,8 @@ class Ey::Core::Client < Cistern::Service
219
222
  request :get_database_servers_firewalls
220
223
  request :get_database_service
221
224
  request :get_database_services
225
+ request :get_deployment
226
+ request :get_deployments
222
227
  request :get_environment
223
228
  request :get_environment_database_services
224
229
  request :get_environment_logical_databases
@@ -274,6 +279,7 @@ class Ey::Core::Client < Cistern::Service
274
279
  request :get_task
275
280
  request :get_tasks
276
281
  request :get_token
282
+ request :get_token_by_login
277
283
  request :get_tokens
278
284
  request :get_untracked_server
279
285
  request :get_untracked_servers
@@ -283,9 +289,11 @@ class Ey::Core::Client < Cistern::Service
283
289
  request :reboot_server
284
290
  request :request_callback
285
291
  request :reset_password
292
+ request :restart_environment_app_servers
286
293
  request :run_cluster_application_action
287
294
  request :run_environment_application_action
288
295
  request :signup
296
+ request :timeout_deployment
289
297
  request :update_addon
290
298
  request :update_address
291
299
  request :update_alert
@@ -298,6 +306,7 @@ class Ey::Core::Client < Cistern::Service
298
306
  request :update_ssl_certificate
299
307
  request :update_untracked_server
300
308
  request :upload_file
309
+ request :upload_recipes_for_environment
301
310
 
302
311
  recognizes :token, :url, :logger, :adapter, :builder, :connection_options, :auth_id, :auth_key, :cache, :config_file
303
312
 
@@ -132,6 +132,7 @@ class Ey::Core::Client::Mock
132
132
  :database_servers => {},
133
133
  :database_services => {},
134
134
  :deleted => Hash.new {|x,y| x[y] = {}},
135
+ :deployments => {},
135
136
  :environment_plan_usages => Hash.new { |h1,k1| h1[k1] = {} },
136
137
  :environments => {},
137
138
  :features => {},
@@ -42,13 +42,13 @@ class Ey::Core::Client::Real
42
42
  end
43
43
 
44
44
  def request(options={})
45
- method = options[:method] || :get
46
- url = options[:url] || File.join(@url, options[:path] || "/")
45
+ method = options[:method] || :get
46
+ url = options[:url] || File.join(@url, options[:path] || "/")
47
47
  #@todo query is a band-aid
48
- query = options[:query] || {}
48
+ query = options[:query] || {}
49
49
  params = query.merge(options[:params] || {})
50
50
  body = options[:body]
51
- headers = options[:headers] || {}
51
+ headers = options[:headers] || {}
52
52
 
53
53
  default_content_type = if !body && !params.empty?
54
54
  "application/x-www-form-urlencoded"
@@ -0,0 +1,8 @@
1
+ class Ey::Core::Client::Deployments < Ey::Core::Collection
2
+ model Ey::Core::Client::Deployment
3
+
4
+ self.model_root = "deployment"
5
+ self.model_request = "get_deployment"
6
+ self.collection_root = "deployments"
7
+ self.collection_request = "get_deployments"
8
+ end
@@ -12,6 +12,7 @@ class Ey::Core::Client::Account < Ey::Core::Model
12
12
  attribute :plan_type
13
13
  attribute :type
14
14
 
15
+ has_many :addresses
15
16
  has_many :applications
16
17
  has_many :deis_clusters
17
18
  has_many :environments
@@ -0,0 +1,23 @@
1
+ class Ey::Core::Client::Deployment < Ey::Core::Model
2
+ extend Ey::Core::Associations
3
+
4
+ identity :id, type: :integer
5
+
6
+ attribute :commit
7
+ attribute :finished_at, type: :time
8
+ attribute :migrate, type: :boolean
9
+ attribute :migrate_command
10
+ attribute :ref
11
+ attribute :resolved_ref
12
+ attribute :started_at, type: :time
13
+ attribute :successful, type: :boolean
14
+
15
+ has_one :account
16
+ has_one :environment
17
+ has_one :application
18
+ has_one :user
19
+
20
+ def timeout(message=nil)
21
+ merge_attributes(self.connection.timeout_deployment("id" => self.id, "message" => message).body["deployment"])
22
+ end
23
+ end
@@ -5,6 +5,7 @@ class Ey::Core::Client::Environment < Ey::Core::Model
5
5
 
6
6
  attribute :classic, type: :boolean
7
7
  attribute :created_at, type: :time
8
+ attribute :custom_recipes
8
9
  attribute :database_stack
9
10
  attribute :deleted_at, type: :time
10
11
  attribute :deploy_method
@@ -15,6 +16,7 @@ class Ey::Core::Client::Environment < Ey::Core::Model
15
16
  attribute :region
16
17
  attribute :release_label
17
18
  attribute :stack_name
19
+ attribute :username
18
20
 
19
21
  has_one :account
20
22
  has_one :database_service
@@ -25,6 +27,7 @@ class Ey::Core::Client::Environment < Ey::Core::Model
25
27
  has_many :servers
26
28
  has_many :applications
27
29
  has_many :logical_databases
30
+ has_many :deployments
28
31
 
29
32
  attr_accessor :application_id
30
33
 
@@ -80,6 +83,40 @@ class Ey::Core::Client::Environment < Ey::Core::Model
80
83
  self.connection.blueprints.new(self.connection.blueprint_environment("id" => self.id, "name" => options["name"]).body["blueprint"])
81
84
  end
82
85
 
86
+ def upload_recipes(file)
87
+ # file should be a StringIO
88
+ self.connection.upload_recipes_for_environment("file" => file, "id" => self.identity)
89
+ end
90
+
91
+ def maintenance(application, action)
92
+ requires :identity
93
+
94
+ params = {
95
+ "id" => self.identity,
96
+ "application_id" => application.id,
97
+ "maintenance" => {
98
+ "action" => action
99
+ }
100
+ }
101
+
102
+ self.connection.requests.new(self.connection.change_environment_maintenance(params).body["request"])
103
+ end
104
+
105
+ def restart_app_servers
106
+ params = {
107
+ "id" => self.identity,
108
+ "application_id" => self.applications.first.id,
109
+ }
110
+
111
+ self.connection.requests.new(self.connection.restart_environment_app_servers(params).body["request"])
112
+ end
113
+
114
+ def download_recipes
115
+ tempfile = Tempfile.new("cookbooks-#{self.name}.tar.gz")
116
+ File.open(tempfile, 'wb') { |f| f.write self.connection.request(url: self.custom_recipes).body }
117
+ tempfile
118
+ end
119
+
83
120
  def boot(options={})
84
121
  options = Cistern::Hash.stringify_keys(options)
85
122
  if options["blueprint_id"]
@@ -0,0 +1,38 @@
1
+ class Ey::Core::Client
2
+ class Real
3
+ def change_environment_maintenance(options={})
4
+ id = options.delete("id")
5
+ url = options.delete("url")
6
+
7
+ request(
8
+ :body => options,
9
+ :method => :put,
10
+ :path => "environments/#{id}/maintenance",
11
+ :url => url,
12
+ )
13
+ end
14
+ end
15
+
16
+ class Mock
17
+ def change_environment_maintenance(options={})
18
+ find(:environments, resource_identity(params))
19
+ request_id = self.uuid
20
+
21
+ request = {
22
+ "id" => request_id,
23
+ "type" => "app_deployment_maintenance",
24
+ "successful" => "true",
25
+ "started_at" => Time.now,
26
+ "finished_at" => nil,
27
+ "resource_url" => nil
28
+ }
29
+
30
+ self.data[:requests][request_id] = request
31
+
32
+ response(
33
+ :body => {"request" => request},
34
+ :status => 200,
35
+ )
36
+ end
37
+ end
38
+ end
@@ -35,7 +35,9 @@ class Ey::Core::Client
35
35
  "classic" => true,
36
36
  "clusters" => url_for("/environments/#{resource_id}/clusters"),
37
37
  "created_at" => Time.now,
38
+ "custom_recipes" => nil,
38
39
  "database_stack" => "postgres9_4",
40
+ "deployments_url" => url_for("/environments/#{resource_id}/deployments"),
39
41
  "id" => resource_id,
40
42
  "internal_private_key" => internal_key[:private_key],
41
43
  "internal_public_key" => internal_key[:public_key],
@@ -45,6 +47,7 @@ class Ey::Core::Client
45
47
  "servers" => url_for("/environments/#{resource_id}/servers"),
46
48
  "stack_name" => "nginx_passenger4",
47
49
  "updated_at" => Time.now,
50
+ "username" => "deploy",
48
51
  )
49
52
 
50
53
  self.data[:environments][resource_id] = resource
@@ -16,9 +16,26 @@ class Ey::Core::Client
16
16
  environment_id = options.delete("id")
17
17
  application_id = options.delete("application_id")
18
18
  request_id = self.uuid
19
+ deployment_id = self.serial_id
19
20
 
20
21
  response(status: 422) unless self.data[:application_deployments].values.detect { |ad| ad[:environment_id] == environment_id && ad[:application_id] == application_id }
21
22
 
23
+ deployment = {
24
+ "account" => find(:environments, environment_id)["account"],
25
+ "application" => url_for("/applications/#{application_id}"),
26
+ "commit" => options["deploy"]["ref"],
27
+ "environment" => url_for("/environments/#{environment_id}"),
28
+ "finished_at" => Time.now,
29
+ "id" => deployment_id,
30
+ "migrate_command" => options["deploy"]["migrate"] ? (options["deploy"]["migrate_command"] || "rake db:migrate") : nil,
31
+ "migrate" => options["deploy"]["migrate"] || false,
32
+ "resolved_ref" => options["deploy"]["ref"],
33
+ "started_at" => Time.now,
34
+ "successful" => true
35
+ }
36
+
37
+ self.data[:deployments][deployment_id] = deployment
38
+
22
39
  request = {
23
40
  "id" => request_id,
24
41
  "type" => "app_deployment",
@@ -0,0 +1,19 @@
1
+ class Ey::Core::Client
2
+ class Real
3
+ def get_deployment(params={})
4
+ id = params.delete("id")
5
+ url = params.delete("url")
6
+
7
+ request(
8
+ :path => "deployments/#{id}",
9
+ :url => url,
10
+ )
11
+ end
12
+ end
13
+
14
+ class Mock
15
+ def get_deployment(params={})
16
+ response(body: {"deployment" => find(:deployments, resource_identity(params))})
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ class Ey::Core::Client
2
+ class Real
3
+ def get_deployments(params={})
4
+ query = Ey::Core.paging_parameters(params)
5
+ url = params.delete("url")
6
+
7
+ request(
8
+ :params => params,
9
+ :path => "/deployments",
10
+ :query => params,
11
+ :url => url,
12
+ )
13
+ end
14
+ end
15
+
16
+ class Mock
17
+ def get_deployments(params={})
18
+ extract_url_params!(params)
19
+
20
+ headers, deployments_page = search_and_page(params, :deployments, search_keys: %w(account environment application))
21
+
22
+ response(
23
+ :body => {"deployments" => deployments_page},
24
+ :status => 200,
25
+ :headers => headers
26
+ )
27
+ end
28
+ end
29
+ end