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.
- 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,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,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
|
data/lib/ey-core/client.rb
CHANGED
@@ -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
|
|
data/lib/ey-core/client/mock.rb
CHANGED
@@ -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 => {},
|
data/lib/ey-core/client/real.rb
CHANGED
@@ -42,13 +42,13 @@ class Ey::Core::Client::Real
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def request(options={})
|
45
|
-
method = options[:method]
|
46
|
-
url = options[:url]
|
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,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
|