conan_deploy 0.0.4 → 0.0.5
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.
- data/lib/conan/application_helper.rb +118 -0
- data/lib/conan/deploy.rb +7 -2
- data/lib/conan/manifest_builder.rb +31 -1
- data/lib/conan/version.rb +1 -1
- metadata +3 -2
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module RestClientExt
|
5
|
+
include RestClient
|
6
|
+
|
7
|
+
RETRIES = 3
|
8
|
+
|
9
|
+
def self.handle_network_error(verb, err, url, tries)
|
10
|
+
additional_tries = tries - 1
|
11
|
+
message = "#{verb} to #{url} failed with (#{err.ai}), retrying #{additional_tries} more times"
|
12
|
+
|
13
|
+
case err
|
14
|
+
when Errno::ETIMEDOUT, Errno::ECONNREFUSED, RestClient::ServerBrokeConnection, RestClient::RequestTimeout
|
15
|
+
puts message
|
16
|
+
sleep 1
|
17
|
+
else
|
18
|
+
raise err
|
19
|
+
end
|
20
|
+
|
21
|
+
additional_tries
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.request_options(verb, url, headers, payload = nil)
|
25
|
+
opts = {
|
26
|
+
:method => verb.downcase.to_sym,
|
27
|
+
:url => url,
|
28
|
+
:headers => headers.clone,
|
29
|
+
:timeout => headers[:timeout] || 10,
|
30
|
+
:open_timeout => headers[:open_timeout] || 10
|
31
|
+
}
|
32
|
+
|
33
|
+
payload ? opts.merge(:payload => payload) : opts
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.execute_request(verb, url, headers, payload = nil, tries = RETRIES, &block)
|
37
|
+
Request.execute(request_options(verb, url, headers, payload),&block)
|
38
|
+
rescue SystemCallError, Exception => err
|
39
|
+
retry unless (tries = handle_network_error(verb, err, url, tries)).zero?
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.get(url, headers={}, &block)
|
43
|
+
execute_request("GET", url, headers, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.post(url, payload, headers={}, &block)
|
47
|
+
execute_request("POST", url, headers, payload, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.put(url, payload, headers={}, &block)
|
51
|
+
execute_request("PUT", url, headers, payload, &block)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.delete(url, headers={}, &block)
|
55
|
+
execute_request("DELETE", url, headers, &block)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module ApiHelper
|
60
|
+
|
61
|
+
def self.defaultHeaders(headers = {})
|
62
|
+
default_headers = {
|
63
|
+
:user_agent => 'CONAN_DA_DEPLOYER',
|
64
|
+
:accept => :json,
|
65
|
+
:accept_encoding => :gzip,
|
66
|
+
:content_type => :json }
|
67
|
+
|
68
|
+
default_headers = default_headers.merge(headers).delete_if { |k, v| v.nil? }
|
69
|
+
return default_headers
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.healthcheck(url, timeout)
|
73
|
+
RestClientExt.get(
|
74
|
+
url,
|
75
|
+
defaultHeaders(
|
76
|
+
:timeout => timeout,
|
77
|
+
:open_timeout => timeout)) do |response, request, result, &block|
|
78
|
+
return NexusResponse.new(response.code, response.body)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class NexusResponse
|
84
|
+
attr_accessor :code
|
85
|
+
attr_accessor :json
|
86
|
+
attr_accessor :raw_json
|
87
|
+
|
88
|
+
def initialize(code, raw_json)
|
89
|
+
@code = code
|
90
|
+
|
91
|
+
begin
|
92
|
+
@json = OpenStruct.new(JSON.parse(Zlib::GzipReader.new(StringIO.new(raw_json)).read))
|
93
|
+
@raw_json = Zlib::GzipReader.new(StringIO.new(raw_json)).read
|
94
|
+
rescue Zlib::Error
|
95
|
+
begin
|
96
|
+
@json = OpenStruct.new(JSON.parse(raw_json))
|
97
|
+
@raw_json = raw_json
|
98
|
+
rescue JSON::ParserError
|
99
|
+
puts "NexusResponse - could not parse following JSON:\n#{raw_json}"
|
100
|
+
@json = OpenStruct.new(JSON.parse("{ \"status\" : \"error\", \"errorMessage\" : \"Previous call likely returned a Stackato HTML error page\" }"))
|
101
|
+
@raw_json = raw_json
|
102
|
+
end
|
103
|
+
rescue Zlib::GzipFile::Error
|
104
|
+
begin
|
105
|
+
@json = OpenStruct.new(JSON.parse(raw_json))
|
106
|
+
@raw_json = raw_json
|
107
|
+
rescue JSON::ParserError
|
108
|
+
puts "NexusResponse - could not parse following JSON:\n#{raw_json}"
|
109
|
+
@json = OpenStruct.new(JSON.parse("{ \"status\" : \"error\", \"errorMessage\" : \"Previous call likely returned a Stackato HTML error page\" }"))
|
110
|
+
@raw_json = raw_json
|
111
|
+
end
|
112
|
+
rescue JSON::ParserError
|
113
|
+
puts "NexusResponse - could not parse following JSON:\n#{raw_json}"
|
114
|
+
@json = OpenStruct.new(JSON.parse("{ \"status\" : \"error\", \"errorMessage\" : \"Previous call likely returned a Stackato HTML error page\" }"))
|
115
|
+
@raw_json = raw_json
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/conan/deploy.rb
CHANGED
@@ -36,8 +36,13 @@ module Conan
|
|
36
36
|
manifest.provision
|
37
37
|
manifest.bg_configure
|
38
38
|
manifest.bg_deploy
|
39
|
-
manifest.
|
40
|
-
|
39
|
+
if(manifest.is_inactive_node_healthy?)
|
40
|
+
manifest.bg_switch
|
41
|
+
manifest.bg_clean
|
42
|
+
else
|
43
|
+
raise RuntimeError.new "Blue node is not healthy. Skipping switch and cleaning to facilitate troubleshooting."
|
44
|
+
end
|
45
|
+
|
41
46
|
else
|
42
47
|
raise ArgumentError.new "Invalid action: #{options[:action]}"
|
43
48
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'rest_client'
|
2
2
|
require 'rexml/document'
|
3
|
-
require 'properties-ruby'
|
4
3
|
require 'json'
|
5
4
|
require 'securerandom'
|
6
5
|
require 'daphne_util'
|
@@ -9,6 +8,7 @@ require 'conan/output'
|
|
9
8
|
require 'conan/repository'
|
10
9
|
require 'conan/stackato'
|
11
10
|
require 'conan/newrelic'
|
11
|
+
require 'conan/application_helper'
|
12
12
|
|
13
13
|
module ManifestBuilder
|
14
14
|
def self.build(options, pipeline_id, env_id, artifact_repo=nil, outthingy=nil, &block)
|
@@ -119,6 +119,12 @@ class Manifest
|
|
119
119
|
@current_pipeline.bg_deploy(@current_environment, paas, force)
|
120
120
|
end
|
121
121
|
|
122
|
+
def is_inactive_node_healthy?
|
123
|
+
validateThatEnvironmentIsSelected
|
124
|
+
puts "Blue/green health check #{@current_environment.id} for #{@current_pipeline.id} pipeline"
|
125
|
+
@current_pipeline.is_inactive_node_healthy?(@current_environment, paas)
|
126
|
+
end
|
127
|
+
|
122
128
|
def bg_switch
|
123
129
|
validateThatEnvironmentIsSelected
|
124
130
|
puts "Blue/green switch #{@current_environment.id} for #{@current_pipeline.id} pipeline"
|
@@ -141,6 +147,8 @@ class Manifest
|
|
141
147
|
end
|
142
148
|
|
143
149
|
class Pipeline
|
150
|
+
include ApiHelper
|
151
|
+
|
144
152
|
attr_accessor :id, :apps
|
145
153
|
|
146
154
|
def initialize(id, artifact_repo, output)
|
@@ -219,6 +227,19 @@ class Pipeline
|
|
219
227
|
}
|
220
228
|
end
|
221
229
|
|
230
|
+
def is_inactive_node_healthy?(environment, paas)
|
231
|
+
eachAppDeployment(environment) { |app, deploy|
|
232
|
+
response = ApiHelper.healthcheck(deploy.inactive_healthcheck_url(app.id), 60)
|
233
|
+
|
234
|
+
if(response.code != 200)
|
235
|
+
puts "Healthcheck failed for inactive (Blue) node. Here is the entire response: #{response.inspect}"
|
236
|
+
return false
|
237
|
+
else
|
238
|
+
return true
|
239
|
+
end
|
240
|
+
}
|
241
|
+
end
|
242
|
+
|
222
243
|
def bg_switch(environment, paas)
|
223
244
|
eachAppDeployment(environment) { |app, deploy| paas.bg_switch(app, deploy) }
|
224
245
|
end
|
@@ -329,6 +350,7 @@ class Application
|
|
329
350
|
res
|
330
351
|
end
|
331
352
|
|
353
|
+
|
332
354
|
def compareVersion(target_version, deployed_version)
|
333
355
|
target = Gem::Version.new(target_version)
|
334
356
|
begin
|
@@ -478,6 +500,14 @@ class Deployment < HasOptions
|
|
478
500
|
"http://#{dns_name(app_id)}/status/manifest"
|
479
501
|
end
|
480
502
|
|
503
|
+
def active_healthcheck_url(app_id)
|
504
|
+
"http://#{dns_name(app_id)}/status/healthcheck"
|
505
|
+
end
|
506
|
+
|
507
|
+
def inactive_healthcheck_url(app_id)
|
508
|
+
"http://inactive.#{dns_name(app_id)}/status/healthcheck"
|
509
|
+
end
|
510
|
+
|
481
511
|
def paas_target
|
482
512
|
"https://api.paas.#{@ship}.#{@org}.#{@@paas_domain}"
|
483
513
|
end
|
data/lib/conan/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: conan_deploy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2014-04-
|
13
|
+
date: 2014-04-25 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: daphne_util
|
@@ -36,6 +36,7 @@ extensions: []
|
|
36
36
|
extra_rdoc_files: []
|
37
37
|
files:
|
38
38
|
- bin/conan
|
39
|
+
- lib/conan/application_helper.rb
|
39
40
|
- lib/conan/deploy.rb
|
40
41
|
- lib/conan/manifest_builder.rb
|
41
42
|
- lib/conan/newrelic.rb
|