aws-codedeploy-agent 0.0.2 → 0.0.3
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/aws-codedeploy-agent.gemspec +5 -5
- data/certs/host-agent-deployment-signer-ca-chain.pem +30 -0
- data/conf/codedeployagent.yml +0 -1
- data/lib/instance_agent.rb +1 -13
- data/lib/instance_agent/agent/base.rb +38 -12
- data/lib/instance_agent/agent/plugin.rb +21 -0
- data/lib/instance_agent/config.rb +2 -1
- data/lib/instance_agent/platform/linux_util.rb +4 -0
- data/lib/instance_agent/plugins/codedeploy/application_specification/ace_info.rb +133 -0
- data/lib/instance_agent/plugins/codedeploy/application_specification/acl_info.rb +163 -0
- data/lib/instance_agent/plugins/codedeploy/application_specification/application_specification.rb +143 -0
- data/lib/instance_agent/plugins/codedeploy/application_specification/context_info.rb +23 -0
- data/lib/instance_agent/plugins/codedeploy/application_specification/file_info.rb +23 -0
- data/lib/instance_agent/plugins/codedeploy/application_specification/linux_permission_info.rb +121 -0
- data/lib/instance_agent/plugins/codedeploy/application_specification/mode_info.rb +66 -0
- data/lib/instance_agent/plugins/codedeploy/application_specification/range_info.rb +134 -0
- data/lib/instance_agent/plugins/codedeploy/application_specification/script_info.rb +27 -0
- data/lib/instance_agent/plugins/codedeploy/codedeploy_control.rb +100 -0
- data/lib/instance_agent/plugins/codedeploy/command_executor.rb +359 -0
- data/lib/instance_agent/plugins/codedeploy/command_poller.rb +178 -0
- data/lib/instance_agent/plugins/codedeploy/deployment_specification.rb +161 -0
- data/lib/instance_agent/plugins/codedeploy/hook_executor.rb +226 -0
- data/lib/instance_agent/plugins/codedeploy/install_instruction.rb +389 -0
- data/lib/instance_agent/plugins/codedeploy/installer.rb +147 -0
- data/lib/instance_agent/plugins/codedeploy/onpremise_config.rb +42 -0
- data/lib/instance_agent/plugins/codedeploy/register_plugin.rb +17 -0
- data/lib/instance_agent/runner/child.rb +20 -5
- data/lib/instance_agent/runner/master.rb +2 -15
- data/lib/instance_metadata.rb +2 -2
- data/test/certificate_helper.rb +1 -1
- data/test/helpers/instance_agent_helper.rb +1 -0
- data/test/instance_agent/agent/base_test.rb +16 -3
- data/test/instance_agent/config_test.rb +2 -1
- data/test/instance_agent/plugins/codedeploy/application_specification_test.rb +1713 -0
- data/test/instance_agent/{codedeploy_plugin → plugins/codedeploy}/codedeploy_control_test.rb +1 -1
- data/test/instance_agent/{codedeploy_plugin → plugins/codedeploy}/command_executor_test.rb +32 -9
- data/test/instance_agent/{codedeploy_plugin → plugins/codedeploy}/command_poller_test.rb +13 -14
- data/test/instance_agent/{codedeploy_plugin → plugins/codedeploy}/deployment_specification_test.rb +98 -25
- data/test/instance_agent/{codedeploy_plugin → plugins/codedeploy}/hook_executor_test.rb +83 -15
- data/test/instance_agent/plugins/codedeploy/install_instruction_test.rb +568 -0
- data/test/instance_agent/{codedeploy_plugin → plugins/codedeploy}/installer_test.rb +12 -9
- data/test/instance_agent/plugins/codedeploy/onpremise_config_test.rb +72 -0
- data/test/instance_agent/runner/child_test.rb +1 -1
- data/vendor/gems/.codedeploy-commands-1.0.0.created.rid +1 -1
- data/vendor/gems/codedeploy-commands/lib/aws/plugins/deploy_control_endpoint.rb +4 -0
- data/vendor/gems/jmespath-1.0.1/lib/jmespath.rb +41 -0
- data/vendor/gems/jmespath-1.0.1/lib/jmespath/caching_parser.rb +30 -0
- data/vendor/gems/jmespath-1.0.1/lib/jmespath/errors.rb +17 -0
- data/vendor/gems/jmespath-1.0.1/lib/jmespath/expr_node.rb +15 -0
- data/vendor/gems/jmespath-1.0.1/lib/jmespath/lexer.rb +116 -0
- data/vendor/gems/jmespath-1.0.1/lib/jmespath/parser.rb +347 -0
- data/vendor/gems/jmespath-1.0.1/lib/jmespath/runtime.rb +71 -0
- data/vendor/gems/jmespath-1.0.1/lib/jmespath/token.rb +41 -0
- data/vendor/gems/jmespath-1.0.1/lib/jmespath/token_stream.rb +60 -0
- data/vendor/gems/jmespath-1.0.1/lib/jmespath/tree_interpreter.rb +523 -0
- data/vendor/gems/jmespath-1.0.1/lib/jmespath/version.rb +3 -0
- data/vendor/gems/process_manager/lib/process_manager/master.rb +16 -5
- data/vendor/specifications/{aws-sdk-core-2.0.5.gemspec → aws-sdk-core-2.0.42.gemspec} +9 -11
- data/vendor/specifications/builder-3.2.2.gemspec +1 -1
- data/vendor/specifications/codedeploy-commands-1.0.0.gemspec +7 -6
- data/vendor/specifications/gli-2.5.6.gemspec +1 -1
- data/vendor/specifications/jmespath-1.0.1.gemspec +29 -0
- data/vendor/specifications/little-plugger-1.1.3.gemspec +1 -1
- data/vendor/specifications/logging-1.8.1.gemspec +1 -1
- data/vendor/specifications/multi_json-1.7.7.gemspec +1 -1
- data/vendor/specifications/multi_json-1.8.4.gemspec +1 -1
- data/vendor/specifications/multi_xml-0.5.5.gemspec +1 -1
- data/vendor/specifications/process_manager-0.0.13.gemspec +1 -1
- data/vendor/specifications/simple_pid-0.2.1.gemspec +1 -1
- metadata +76 -63
- data/lib/instance_agent/codedeploy_plugin/application_specification/ace_info.rb +0 -133
- data/lib/instance_agent/codedeploy_plugin/application_specification/acl_info.rb +0 -163
- data/lib/instance_agent/codedeploy_plugin/application_specification/application_specification.rb +0 -142
- data/lib/instance_agent/codedeploy_plugin/application_specification/context_info.rb +0 -23
- data/lib/instance_agent/codedeploy_plugin/application_specification/file_info.rb +0 -23
- data/lib/instance_agent/codedeploy_plugin/application_specification/linux_permission_info.rb +0 -121
- data/lib/instance_agent/codedeploy_plugin/application_specification/mode_info.rb +0 -66
- data/lib/instance_agent/codedeploy_plugin/application_specification/range_info.rb +0 -134
- data/lib/instance_agent/codedeploy_plugin/application_specification/script_info.rb +0 -27
- data/lib/instance_agent/codedeploy_plugin/codedeploy_control.rb +0 -72
- data/lib/instance_agent/codedeploy_plugin/command_executor.rb +0 -357
- data/lib/instance_agent/codedeploy_plugin/command_poller.rb +0 -170
- data/lib/instance_agent/codedeploy_plugin/deployment_specification.rb +0 -150
- data/lib/instance_agent/codedeploy_plugin/hook_executor.rb +0 -206
- data/lib/instance_agent/codedeploy_plugin/install_instruction.rb +0 -374
- data/lib/instance_agent/codedeploy_plugin/installer.rb +0 -143
- data/lib/instance_agent/codedeploy_plugin/request_helper.rb +0 -28
- data/test/instance_agent/codedeploy_plugin/application_specification_test.rb +0 -1710
- data/test/instance_agent/codedeploy_plugin/install_instruction_test.rb +0 -566
- data/test/instance_agent/codedeploy_plugin/request_helper_test.rb +0 -37
- data/vendor/specifications/jamespath-0.5.1.gemspec +0 -35
|
@@ -1,357 +0,0 @@
|
|
|
1
|
-
require 'openssl'
|
|
2
|
-
require 'fileutils'
|
|
3
|
-
require 'instance_agent/codedeploy_plugin/installer'
|
|
4
|
-
require 'instance_agent/codedeploy_plugin/hook_executor'
|
|
5
|
-
require 'aws-sdk-core'
|
|
6
|
-
require 'zlib'
|
|
7
|
-
require 'zip'
|
|
8
|
-
require 'instance_metadata'
|
|
9
|
-
require 'open-uri'
|
|
10
|
-
require 'uri'
|
|
11
|
-
|
|
12
|
-
module InstanceAgent
|
|
13
|
-
module CodeDeployPlugin
|
|
14
|
-
ARCHIVES_TO_RETAIN = 5
|
|
15
|
-
class CommandExecutor
|
|
16
|
-
class << self
|
|
17
|
-
attr_reader :command_methods
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
attr_reader :deployment_system
|
|
21
|
-
|
|
22
|
-
InvalidCommandNameFailure = Class.new(Exception)
|
|
23
|
-
|
|
24
|
-
def initialize(options = {})
|
|
25
|
-
@deployment_system = "CodeDeploy"
|
|
26
|
-
@deploy_control_client = options[:deploy_control_client]
|
|
27
|
-
@hook_mapping = options[:hook_mapping]
|
|
28
|
-
if(!@hook_mapping.nil?)
|
|
29
|
-
map
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def self.command(name, &blk)
|
|
34
|
-
@command_methods ||= Hash.new
|
|
35
|
-
|
|
36
|
-
method = Seahorse::Util.underscore(name).to_sym
|
|
37
|
-
@command_methods[name] = method
|
|
38
|
-
|
|
39
|
-
define_method(method, &blk)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def execute_command(command, deployment_specification)
|
|
43
|
-
method_name = command_method(command.command_name)
|
|
44
|
-
log(:debug, "Command #{command.command_name} maps to method #{method_name}")
|
|
45
|
-
|
|
46
|
-
deployment_specification = DeploymentSpecification.parse(deployment_specification)
|
|
47
|
-
log(:debug, "Successfully parsed the deployment spec")
|
|
48
|
-
|
|
49
|
-
log(:debug, "Creating deployment root directory #{deployment_root_dir(deployment_specification)}")
|
|
50
|
-
FileUtils.mkdir_p(deployment_root_dir(deployment_specification))
|
|
51
|
-
raise "Error creating deployment root directory #{deployment_root_dir(deployment_specification)}" if !File.directory?(deployment_root_dir(deployment_specification))
|
|
52
|
-
|
|
53
|
-
send(method_name, command, deployment_specification)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def command_method(command_name)
|
|
57
|
-
raise InvalidCommandNameFailure.new("Unsupported command type: #{command_name}.") unless self.class.command_methods.has_key?(command_name)
|
|
58
|
-
self.class.command_methods[command_name]
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
command "DownloadBundle" do |cmd, deployment_spec|
|
|
62
|
-
cleanup_old_archives(deployment_spec.deployment_group_id)
|
|
63
|
-
log(:debug, "Executing DownloadBundle command for execution #{cmd.deployment_execution_id}")
|
|
64
|
-
|
|
65
|
-
case deployment_spec.revision_source
|
|
66
|
-
when 'S3'
|
|
67
|
-
download_from_s3(
|
|
68
|
-
deployment_spec,
|
|
69
|
-
deployment_spec.bucket,
|
|
70
|
-
deployment_spec.key,
|
|
71
|
-
deployment_spec.version,
|
|
72
|
-
deployment_spec.etag)
|
|
73
|
-
when 'GitHub'
|
|
74
|
-
download_from_github(
|
|
75
|
-
deployment_spec,
|
|
76
|
-
deployment_spec.external_account,
|
|
77
|
-
deployment_spec.repository,
|
|
78
|
-
deployment_spec.commit_id,
|
|
79
|
-
deployment_spec.anonymous,
|
|
80
|
-
deployment_spec.external_auth_token)
|
|
81
|
-
else
|
|
82
|
-
# This should never happen since this is checked during creation of the deployment_spec object.
|
|
83
|
-
raise "Unknown revision type '#{deployment_spec.revision_source}'"
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
FileUtils.rm_rf(File.join(deployment_root_dir(deployment_spec), 'deployment-archive'))
|
|
87
|
-
bundle_file = artifact_bundle(deployment_spec)
|
|
88
|
-
|
|
89
|
-
unpack_bundle(cmd, bundle_file, deployment_spec)
|
|
90
|
-
|
|
91
|
-
nil
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
command "Install" do |cmd, deployment_spec|
|
|
95
|
-
log(:debug, "Executing Install command for execution #{cmd.deployment_execution_id}")
|
|
96
|
-
|
|
97
|
-
FileUtils.mkdir_p(deployment_instructions_dir)
|
|
98
|
-
log(:debug, "Instructions directory created at #{deployment_instructions_dir}")
|
|
99
|
-
|
|
100
|
-
installer = Installer.new(:deployment_instructions_dir => deployment_instructions_dir,
|
|
101
|
-
:deployment_archive_dir => archive_root_dir(deployment_spec))
|
|
102
|
-
|
|
103
|
-
log(:debug, "Installing revision #{deployment_spec.revision} in "+
|
|
104
|
-
"instance group #{deployment_spec.deployment_group_id}")
|
|
105
|
-
installer.install(deployment_spec.deployment_group_id, default_app_spec(deployment_spec))
|
|
106
|
-
update_last_successful_install(deployment_spec)
|
|
107
|
-
nil
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def map
|
|
111
|
-
@hook_mapping.each_pair do |command, lifecycle_events|
|
|
112
|
-
InstanceAgent::CodeDeployPlugin::CommandExecutor.command command do |cmd, deployment_spec|
|
|
113
|
-
#run the scripts
|
|
114
|
-
script_log = ScriptLog.new
|
|
115
|
-
lifecycle_events.each do |lifecycle_event|
|
|
116
|
-
hook_command = HookExecutor.new(:lifecycle_event => lifecycle_event,
|
|
117
|
-
:deployment_root_dir => deployment_root_dir(deployment_spec),
|
|
118
|
-
:last_successful_deployment_dir => last_successful_deployment_dir(deployment_spec.deployment_group_id),
|
|
119
|
-
:app_spec_path => app_spec_path)
|
|
120
|
-
script_log.concat_log(hook_command.execute)
|
|
121
|
-
end
|
|
122
|
-
script_log.log
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
private
|
|
128
|
-
def deployment_root_dir(deployment_spec)
|
|
129
|
-
File.join(ProcessManager::Config.config[:root_dir], deployment_spec.deployment_group_id, deployment_spec.deployment_id)
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
private
|
|
133
|
-
def deployment_instructions_dir()
|
|
134
|
-
File.join(ProcessManager::Config.config[:root_dir], 'deployment-instructions')
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
private
|
|
138
|
-
def archive_root_dir(deployment_spec)
|
|
139
|
-
File.join(deployment_root_dir(deployment_spec), 'deployment-archive')
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
private
|
|
143
|
-
def last_successful_deployment_dir(deployment_group)
|
|
144
|
-
last_install_file_location = last_install_file_path(deployment_group)
|
|
145
|
-
return unless File.exist? last_install_file_location
|
|
146
|
-
File.open last_install_file_location do |f|
|
|
147
|
-
return f.read.chomp
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
private
|
|
152
|
-
def default_app_spec(deployment_spec)
|
|
153
|
-
default_app_spec_location = File.join(archive_root_dir(deployment_spec), app_spec_path)
|
|
154
|
-
log(:debug, "Checking for app spec in #{default_app_spec_location}")
|
|
155
|
-
app_spec = ApplicationSpecification::ApplicationSpecification.parse(File.read(default_app_spec_location))
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
private
|
|
159
|
-
def last_install_file_path(deployment_group)
|
|
160
|
-
File.join(deployment_instructions_dir, "#{deployment_group}_last_successful_install")
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
private
|
|
164
|
-
def download_from_s3(deployment_spec, bucket, key, version, etag)
|
|
165
|
-
log(:debug, "Downloading artifact bundle from bucket '#{bucket}' and key '#{key}', version '#{version}', etag '#{etag}'")
|
|
166
|
-
region = ENV['AWS_REGION'] || InstanceMetadata.region
|
|
167
|
-
|
|
168
|
-
if InstanceAgent::Config.config[:log_aws_wire]
|
|
169
|
-
s3 = Aws::S3::Client.new(
|
|
170
|
-
:region => region,
|
|
171
|
-
:ssl_ca_directory => ENV['AWS_SSL_CA_DIRECTORY'],
|
|
172
|
-
# wire logs might be huge; customers should be careful about turning them on
|
|
173
|
-
# allow 1GB of old wire logs in 64MB chunks
|
|
174
|
-
:logger => Logger.new(
|
|
175
|
-
File.join(InstanceAgent::Config.config[:log_dir], "#{InstanceAgent::Config.config[:program_name]}.aws_wire.log"),
|
|
176
|
-
16,
|
|
177
|
-
64 * 1024 * 1024),
|
|
178
|
-
:http_wire_trace => true)
|
|
179
|
-
else
|
|
180
|
-
s3 = Aws::S3::Client.new(
|
|
181
|
-
:region => region,
|
|
182
|
-
:ssl_ca_directory => ENV['AWS_SSL_CA_DIRECTORY'])
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
File.open(artifact_bundle(deployment_spec), 'wb') do |file|
|
|
186
|
-
|
|
187
|
-
if !version.nil?
|
|
188
|
-
object = s3.get_object({:bucket => bucket, :key => key, :version_id => version}, :target => file)
|
|
189
|
-
else
|
|
190
|
-
object = s3.get_object({:bucket => bucket, :key => key}, :target => file)
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
if(!etag.nil? && !(etag.gsub(/"/,'').eql? object.etag.gsub(/"/,'')))
|
|
194
|
-
msg = "Expected deployment artifact bundle etag #{etag} but was actually #{object.etag}"
|
|
195
|
-
log(:error, msg)
|
|
196
|
-
raise RuntimeError, msg
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
log(:debug, "Download complete from bucket #{bucket} and key #{key}")
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
private
|
|
203
|
-
def download_from_github(deployment_spec, account, repo, commit, anonymous, token)
|
|
204
|
-
|
|
205
|
-
retries = 0
|
|
206
|
-
errors = []
|
|
207
|
-
|
|
208
|
-
if InstanceAgent::Platform.util.supported_oses == 'windows'
|
|
209
|
-
deployment_spec.bundle_type = 'zip'
|
|
210
|
-
format = 'zipball'
|
|
211
|
-
else
|
|
212
|
-
deployment_spec.bundle_type = 'tar'
|
|
213
|
-
format = 'tarball'
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
uri = URI.parse("https://api.github.com/repos/#{account}/#{repo}/#{format}/#{commit}")
|
|
217
|
-
options = {:ssl_verify_mode => OpenSSL::SSL::VERIFY_PEER, :redirect => true, :ssl_ca_cert => ENV['AWS_SSL_CA_DIRECTORY']}
|
|
218
|
-
|
|
219
|
-
if anonymous
|
|
220
|
-
log(:debug, "Anonymous GitHub repository download requested.")
|
|
221
|
-
else
|
|
222
|
-
log(:debug, "Authenticated GitHub repository download requested.")
|
|
223
|
-
options.update({'Authorization' => "token #{token}"})
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
begin
|
|
227
|
-
# stream bundle file to disk
|
|
228
|
-
log(:info, "Requesting URL: '#{uri.to_s}'")
|
|
229
|
-
File.open(artifact_bundle(deployment_spec), 'w+b') do |file|
|
|
230
|
-
uri.open(options) do |github|
|
|
231
|
-
log(:debug, "GitHub response: '#{github.meta.to_s}'")
|
|
232
|
-
|
|
233
|
-
while (buffer = github.read(8 * 1024 * 1024))
|
|
234
|
-
file.write buffer
|
|
235
|
-
end
|
|
236
|
-
end
|
|
237
|
-
end
|
|
238
|
-
rescue OpenURI::HTTPError => e
|
|
239
|
-
log(:error, "Could not download bundle at '#{uri.to_s}'. Server returned code #{e.io.status[0]} '#{e.io.status[1]}'")
|
|
240
|
-
log(:debug, "Server returned error response body #{e.io.string}")
|
|
241
|
-
errors << "#{e.io.status[0]} '#{e.io.status[1]}'"
|
|
242
|
-
|
|
243
|
-
if retries < 3
|
|
244
|
-
time_to_sleep = (10 * (3 ** retries)) # 10 sec, 30 sec, 90 sec
|
|
245
|
-
log(:debug, "Retrying download in #{time_to_sleep} seconds.")
|
|
246
|
-
sleep(time_to_sleep)
|
|
247
|
-
retries += 1
|
|
248
|
-
retry
|
|
249
|
-
else
|
|
250
|
-
raise "Could not download bundle at '#{uri.to_s}' after #{retries} retries. Server returned codes: #{errors.join("; ")}."
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
private
|
|
256
|
-
def unpack_bundle(cmd, bundle_file, deployment_spec)
|
|
257
|
-
strip_leading_directory = deployment_spec.revision_source == 'GitHub'
|
|
258
|
-
|
|
259
|
-
if strip_leading_directory
|
|
260
|
-
# Extract to a temporary directory first so we can move the files around
|
|
261
|
-
dst = File.join(deployment_root_dir(deployment_spec), 'deployment-archive-temp')
|
|
262
|
-
actual_dst = File.join(deployment_root_dir(deployment_spec), 'deployment-archive')
|
|
263
|
-
FileUtils.rm_rf(dst)
|
|
264
|
-
else
|
|
265
|
-
dst = File.join(deployment_root_dir(deployment_spec), 'deployment-archive')
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
if "tar".eql? deployment_spec.bundle_type
|
|
269
|
-
InstanceAgent::Platform.util.extract_tar(bundle_file, dst)
|
|
270
|
-
elsif "tgz".eql? deployment_spec.bundle_type
|
|
271
|
-
InstanceAgent::Platform.util.extract_tgz(bundle_file, dst)
|
|
272
|
-
elsif "zip".eql? deployment_spec.bundle_type
|
|
273
|
-
Zip::File.open(bundle_file) do |zipfile|
|
|
274
|
-
zipfile.each do |f|
|
|
275
|
-
file_dst = File.join(dst, f.name)
|
|
276
|
-
FileUtils.mkdir_p(File.dirname(file_dst))
|
|
277
|
-
zipfile.extract(f, file_dst)
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
else
|
|
281
|
-
# If the bundle was a generated through a Sabini Repository
|
|
282
|
-
# it will be in tar format, and it won't have a bundle type
|
|
283
|
-
InstanceAgent::Platform.util.extract_tar(bundle_file, dst)
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
if strip_leading_directory
|
|
287
|
-
log(:info, "Stripping leading directory from archive bundle contents.")
|
|
288
|
-
|
|
289
|
-
# Find leading directory to remove
|
|
290
|
-
archive_root_files = Dir.entries(dst)
|
|
291
|
-
archive_root_files.delete_if { |name| name == '.' || name == '..' }
|
|
292
|
-
|
|
293
|
-
if (archive_root_files.size != 1)
|
|
294
|
-
log(:warn, "Expected archive to have a single root directory containing the actual bundle root, but it had #{archive_root_files.size} entries instead. Skipping leading directory removal and using archive as is.")
|
|
295
|
-
FileUtils.mv(dst, actual_dst)
|
|
296
|
-
return
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
nested_archive_root = File.join(dst, archive_root_files[0])
|
|
300
|
-
log(:debug, "Actual archive root at #{nested_archive_root}. Moving to #{actual_dst}")
|
|
301
|
-
|
|
302
|
-
FileUtils.mv(nested_archive_root, actual_dst)
|
|
303
|
-
FileUtils.rmdir(dst)
|
|
304
|
-
|
|
305
|
-
log(:debug, Dir.entries(actual_dst).join("; "))
|
|
306
|
-
end
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
private
|
|
310
|
-
def update_last_successful_install(deployment_spec)
|
|
311
|
-
File.open(last_install_file_path(deployment_spec.deployment_group_id), 'w+') do |f|
|
|
312
|
-
f.write deployment_root_dir(deployment_spec)
|
|
313
|
-
end
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
private
|
|
317
|
-
def cleanup_old_archives(deployment_group)
|
|
318
|
-
deployment_archives = Dir[File.join(ProcessManager::Config.config[:root_dir], deployment_group, '*')]
|
|
319
|
-
extra = deployment_archives.size - ARCHIVES_TO_RETAIN
|
|
320
|
-
return unless extra > 0
|
|
321
|
-
|
|
322
|
-
# Never remove the last successful deployment
|
|
323
|
-
last_success = last_successful_deployment_dir(deployment_group)
|
|
324
|
-
deployment_archives.delete(last_success)
|
|
325
|
-
|
|
326
|
-
# Sort oldest -> newest, take first `extra` elements
|
|
327
|
-
oldest_extra = deployment_archives.sort_by{ |f| File.mtime(f) }.take(extra)
|
|
328
|
-
|
|
329
|
-
# Absolute path takes care of relative root directories
|
|
330
|
-
directories = oldest_extra.map{ |f| File.absolute_path(f) }
|
|
331
|
-
FileUtils.rm_rf(directories)
|
|
332
|
-
|
|
333
|
-
end
|
|
334
|
-
|
|
335
|
-
private
|
|
336
|
-
def artifact_bundle(deployment_spec)
|
|
337
|
-
File.join(deployment_root_dir(deployment_spec), 'bundle.tar')
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
private
|
|
341
|
-
def app_spec_path
|
|
342
|
-
'appspec.yml'
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
private
|
|
346
|
-
def description
|
|
347
|
-
self.class.to_s
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
private
|
|
351
|
-
def log(severity, message)
|
|
352
|
-
raise ArgumentError, "Unknown severity #{severity.inspect}" unless InstanceAgent::Log::SEVERITIES.include?(severity.to_s)
|
|
353
|
-
InstanceAgent::Log.send(severity.to_sym, "#{description}: #{message}")
|
|
354
|
-
end
|
|
355
|
-
end
|
|
356
|
-
end
|
|
357
|
-
end
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
require 'instance_agent/codedeploy_plugin/command_executor'
|
|
2
|
-
require 'instance_metadata'
|
|
3
|
-
require 'socket'
|
|
4
|
-
require 'instance_agent/codedeploy_plugin/codedeploy_control'
|
|
5
|
-
|
|
6
|
-
module InstanceAgent
|
|
7
|
-
module CodeDeployPlugin
|
|
8
|
-
class CommandPoller < InstanceAgent::Agent::Base
|
|
9
|
-
|
|
10
|
-
VERSION = "2013-04-23"
|
|
11
|
-
|
|
12
|
-
def initialize
|
|
13
|
-
region = ENV['AWS_REGION'] || InstanceMetadata.region
|
|
14
|
-
@host_identifier = ENV['AWS_HOST_IDENTIFIER'] || InstanceMetadata.host_identifier
|
|
15
|
-
|
|
16
|
-
log(:debug, "Configuring deploy control client: Region = #{region.inspect}")
|
|
17
|
-
log(:debug, "Deploy control endpoint override = " + ENV['AWS_DEPLOY_CONTROL_ENDPOINT'].inspect)
|
|
18
|
-
|
|
19
|
-
@deploy_control_client = InstanceAgent::CodeDeployPlugin::CodeDeployControl.new(:region => region, :logger => InstanceAgent::Log, :ssl_ca_directory => ENV['AWS_SSL_CA_DIRECTORY']).get_client
|
|
20
|
-
|
|
21
|
-
@plugin = InstanceAgent::CodeDeployPlugin::CommandExecutor.new(
|
|
22
|
-
:deploy_control_client => @deploy_control_client,
|
|
23
|
-
:hook_mapping => create_hook_mapping)
|
|
24
|
-
|
|
25
|
-
log(:debug, "Initializing Host Agent: " +
|
|
26
|
-
"Host Identifier = #{@host_identifier}")
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def create_hook_mapping
|
|
30
|
-
#Map commands to lifecycle hooks
|
|
31
|
-
{ "BeforeELBRemove"=>["BeforeELBRemove"],
|
|
32
|
-
"AfterELBRemove"=>["AfterELBRemove"],
|
|
33
|
-
"ApplicationStop"=>["ApplicationStop"],
|
|
34
|
-
"BeforeInstall"=>["BeforeInstall"],
|
|
35
|
-
"AfterInstall"=>["AfterInstall"],
|
|
36
|
-
"ApplicationStart"=>["ApplicationStart"],
|
|
37
|
-
"BeforeELBAdd"=>["BeforeELBAdd"],
|
|
38
|
-
"AfterELBAdd"=>["AfterELBAdd"],
|
|
39
|
-
"ValidateService"=>["ValidateService"]}
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def perform
|
|
43
|
-
return unless command = next_command
|
|
44
|
-
return unless acknowledge_command(command)
|
|
45
|
-
|
|
46
|
-
begin
|
|
47
|
-
spec = get_deployment_specification(command)
|
|
48
|
-
#Successful commands will complete without raising an exception
|
|
49
|
-
script_output = process_command(command, spec)
|
|
50
|
-
log(:debug, 'Calling PutHostCommandComplete: "Succeeded"')
|
|
51
|
-
@deploy_control_client.put_host_command_complete(
|
|
52
|
-
:command_status => 'Succeeded',
|
|
53
|
-
:diagnostics => {:format => "JSON", :payload => gather_diagnostics()},
|
|
54
|
-
:host_command_identifier => command.host_command_identifier)
|
|
55
|
-
|
|
56
|
-
#Commands that throw an exception will be considered to have failed
|
|
57
|
-
rescue ScriptError => e
|
|
58
|
-
log(:debug, 'Calling PutHostCommandComplete: "Code Error" ')
|
|
59
|
-
@deploy_control_client.put_host_command_complete(
|
|
60
|
-
:command_status => "Failed",
|
|
61
|
-
:diagnostics => {:format => "JSON", :payload => gather_diagnostics_from_script_error(e)},
|
|
62
|
-
:host_command_identifier => command.host_command_identifier)
|
|
63
|
-
raise e
|
|
64
|
-
rescue Exception => e
|
|
65
|
-
log(:debug, 'Calling PutHostCommandComplete: "Code Error" ')
|
|
66
|
-
@deploy_control_client.put_host_command_complete(
|
|
67
|
-
:command_status => "Failed",
|
|
68
|
-
:diagnostics => {:format => "JSON", :payload => gather_diagnostics_from_error(e)},
|
|
69
|
-
:host_command_identifier => command.host_command_identifier)
|
|
70
|
-
raise e
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def next_command
|
|
75
|
-
log(:debug, "Calling PollHostCommand:")
|
|
76
|
-
output = @deploy_control_client.poll_host_command(:host_identifier => @host_identifier)
|
|
77
|
-
command = output.host_command
|
|
78
|
-
if command.nil?
|
|
79
|
-
log(:debug, "PollHostCommand: Host Command = nil")
|
|
80
|
-
else
|
|
81
|
-
log(:debug, "PollHostCommand: " +
|
|
82
|
-
"Host Identifier = #{command.host_identifier}; " +
|
|
83
|
-
"Host Command Identifier = #{command.host_command_identifier}; " +
|
|
84
|
-
"Deployment Execution ID = #{command.deployment_execution_id}; " +
|
|
85
|
-
"Command Name = #{command.command_name}")
|
|
86
|
-
raise "Host Identifier mismatch: #{@host_identifier} != #{command.host_identifier}" unless @host_identifier.include? command.host_identifier
|
|
87
|
-
raise "Command Name missing" if command.command_name.nil? || command.command_name.empty?
|
|
88
|
-
end
|
|
89
|
-
command
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def acknowledge_command(command)
|
|
93
|
-
log(:debug, "Calling PutHostCommandAcknowledgement:")
|
|
94
|
-
output = @deploy_control_client.put_host_command_acknowledgement(
|
|
95
|
-
:diagnostics => nil,
|
|
96
|
-
:host_command_identifier => command.host_command_identifier)
|
|
97
|
-
status = output.command_status
|
|
98
|
-
log(:debug, "Command Status = #{status}")
|
|
99
|
-
|
|
100
|
-
if status == 'Succeeded' || status == 'Failed'
|
|
101
|
-
log(:debug, "Calling PutHostCommandComplete: \"#{status}\" ")
|
|
102
|
-
@deploy_control_client.put_host_command_complete(
|
|
103
|
-
:command_status => status,
|
|
104
|
-
:diagnostics => {:format => "JSON", :payload => gather_diagnostics_from_acknowledge(status)},
|
|
105
|
-
:host_command_identifier => command.host_command_identifier)
|
|
106
|
-
return false
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
return true
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def get_deployment_specification(command)
|
|
113
|
-
log(:debug, "Calling GetDeploymentSpecification:")
|
|
114
|
-
output = @deploy_control_client.get_deployment_specification(
|
|
115
|
-
:deployment_execution_id => command.deployment_execution_id,
|
|
116
|
-
:host_identifier => @host_identifier)
|
|
117
|
-
log(:debug, "GetDeploymentSpecification: " +
|
|
118
|
-
"Deployment System = #{output.deployment_system}")
|
|
119
|
-
raise "Deployment System mismatch: #{@plugin.deployment_system} != #{output.deployment_system}" unless @plugin.deployment_system == output.deployment_system
|
|
120
|
-
raise "Deployment Specification missing" if output.deployment_specification.nil?
|
|
121
|
-
output.deployment_specification.generic_envelope
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def process_command(command, spec)
|
|
125
|
-
log(:debug, "Calling #{@plugin.to_s}.execute_command")
|
|
126
|
-
@plugin.execute_command(command, spec)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
private
|
|
130
|
-
def gather_diagnostics_from_script_error(script_error)
|
|
131
|
-
script_error.to_json
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
private
|
|
135
|
-
def gather_diagnostics_from_error(error)
|
|
136
|
-
begin
|
|
137
|
-
message = error.message || ""
|
|
138
|
-
raise ScriptError.new(ScriptError::UNKNOWN_ERROR_CODE, "", ScriptLog.new), message
|
|
139
|
-
rescue ScriptError => e
|
|
140
|
-
script_error = e
|
|
141
|
-
end
|
|
142
|
-
gather_diagnostics_from_script_error(script_error)
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
private
|
|
146
|
-
def gather_diagnostics()
|
|
147
|
-
begin
|
|
148
|
-
raise ScriptError.new(ScriptError::SUCCEEDED_CODE, "", ScriptLog.new), 'Succeeded'
|
|
149
|
-
rescue ScriptError => e
|
|
150
|
-
script_error = e
|
|
151
|
-
end
|
|
152
|
-
gather_diagnostics_from_script_error(script_error)
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
private
|
|
156
|
-
def gather_diagnostics_from_acknowledge(status)
|
|
157
|
-
begin
|
|
158
|
-
if status == 'Succeeded'
|
|
159
|
-
raise ScriptError.new(ScriptError::SUCCEEDED_CODE, "", ScriptLog.new), 'Succeeded'
|
|
160
|
-
else
|
|
161
|
-
raise ScriptError.new(ScriptError::UNKNOWN_ERROR_CODE, "", ScriptLog.new), 'Failed'
|
|
162
|
-
end
|
|
163
|
-
rescue ScriptError => e
|
|
164
|
-
script_error = e
|
|
165
|
-
end
|
|
166
|
-
gather_diagnostics_from_script_error(script_error)
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
end
|