right_link 5.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/actors/agent_manager.rb +88 -0
- data/actors/instance_scheduler.rb +321 -0
- data/actors/instance_services.rb +64 -0
- data/actors/instance_setup.rb +567 -0
- data/bin/cloud +25 -0
- data/bin/cook_runner +44 -0
- data/bin/deploy +120 -0
- data/bin/enroll +385 -0
- data/bin/rad +32 -0
- data/bin/rchk +29 -0
- data/bin/rnac +39 -0
- data/bin/rs_connect +33 -0
- data/bin/rs_log_level +31 -0
- data/bin/rs_ohai +28 -0
- data/bin/rs_reenroll +31 -0
- data/bin/rs_run_recipe +34 -0
- data/bin/rs_run_right_script +34 -0
- data/bin/rs_shutdown +33 -0
- data/bin/rs_tag +33 -0
- data/bin/rs_thunk +33 -0
- data/bin/rstat +31 -0
- data/bin/system +16 -0
- data/ext/Rakefile +18 -0
- data/init/config.yml +5 -0
- data/init/init.rb +79 -0
- data/lib/chef/ohai_setup.rb +51 -0
- data/lib/chef/plugins/cloud.rb +91 -0
- data/lib/chef/plugins/cloudstack.rb +23 -0
- data/lib/chef/plugins/ec2.rb +23 -0
- data/lib/chef/plugins/linux/block_device2.rb +24 -0
- data/lib/chef/plugins/rackspace.rb +23 -0
- data/lib/chef/plugins/rightscale.rb +125 -0
- data/lib/chef/plugins/windows/network.rb +114 -0
- data/lib/chef/plugins.rb +74 -0
- data/lib/chef/providers/dns_dnsmadeeasy_provider.rb +81 -0
- data/lib/chef/providers/dns_resource.rb +100 -0
- data/lib/chef/providers/executable_schedule_provider.rb +70 -0
- data/lib/chef/providers/executable_schedule_resource.rb +144 -0
- data/lib/chef/providers/remote_recipe_provider.rb +86 -0
- data/lib/chef/providers/remote_recipe_resource.rb +101 -0
- data/lib/chef/providers/right_link_tag_provider.rb +73 -0
- data/lib/chef/providers/right_link_tag_resource.rb +59 -0
- data/lib/chef/providers/right_script_provider.rb +190 -0
- data/lib/chef/providers/right_script_resource.rb +113 -0
- data/lib/chef/providers/rs_shutdown_provider.rb +75 -0
- data/lib/chef/providers/rs_shutdown_resource.rb +55 -0
- data/lib/chef/providers/server_collection_provider.rb +66 -0
- data/lib/chef/providers/server_collection_resource.rb +93 -0
- data/lib/chef/providers/windows/powershell_provider.rb +151 -0
- data/lib/chef/providers/windows/powershell_resource.rb +111 -0
- data/lib/chef/providers/windows/unsupported_provider.rb +51 -0
- data/lib/chef/right_providers.rb +55 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ChefNodeCmdlet.csproj +104 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ChefNodeCmdlet.dll-Help.xml +141 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/Exceptions.cs +182 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetChefNodeCommand.cs +58 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetChefNodeRequest.cs +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetChefNodeResponse.cs +45 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetCurrentResourceCommand.cs +58 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetCurrentResourceRequest.cs +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetCurrentResourceResponse.cs +45 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNewResourceCommand.cs +58 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNewResourceRequest.cs +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNewResourceResponse.cs +45 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNextActionCommand.cs +178 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNextActionRequest.cs +67 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNextActionResponse.cs +58 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNodeValueCommandBase.cs +142 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNodeValueRequestBase.cs +64 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNodeValueResponseBase.cs +69 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/JsonTransport.cs +110 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/PipeClient.cs +158 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/PipeServer.cs +142 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/Properties/AssemblyInfo.cs +16 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ProtocolConstants.cs +55 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ProtocolUtilities.cs +77 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ReadMe.txt +53 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetChefNodeCommand.cs +59 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetChefNodeRequest.cs +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetChefNodeResponse.cs +58 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetCurrentResourceCommand.cs +59 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetCurrentResourceRequest.cs +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetCurrentResourceResponse.cs +40 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNewResourceCommand.cs +59 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNewResourceRequest.cs +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNewResourceResponse.cs +40 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNodeValueCommandBase.cs +293 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNodeValueRequestBase.cs +75 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNodeValueResponseBase.cs +45 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/Transport.cs +91 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet.sln +35 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestChefNodeCmdlet/Program.cs +374 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestChefNodeCmdlet/Properties/AssemblyInfo.cs +16 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestChefNodeCmdlet/TestChefNodeCmdlet.csproj +65 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/Program.cs +136 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/Properties/AssemblyInfo.cs +36 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/ReadMe.txt +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/TestNextActionCmdlet.csproj +68 -0
- data/lib/chef/windows/bin/Newtonsoft.Json.dll +0 -0
- data/lib/chef/windows/chef_node_server.rb +463 -0
- data/lib/chef/windows/dynamic_powershell_provider.rb +296 -0
- data/lib/chef/windows/pipe_server.rb +283 -0
- data/lib/chef/windows/powershell_host.rb +285 -0
- data/lib/chef/windows/powershell_pipe_server.rb +136 -0
- data/lib/chef/windows/powershell_provider_base.rb +92 -0
- data/lib/chef/windows/scripts/run_loop.ps1 +105 -0
- data/lib/clouds/cloud.rb +557 -0
- data/lib/clouds/cloud_factory.rb +250 -0
- data/lib/clouds/cloud_utilities.rb +244 -0
- data/lib/clouds/clouds/azure.rb +106 -0
- data/lib/clouds/clouds/cloudstack.rb +114 -0
- data/lib/clouds/clouds/ec2.rb +113 -0
- data/lib/clouds/clouds/eucalyptus.rb +46 -0
- data/lib/clouds/clouds/google.rb +102 -0
- data/lib/clouds/clouds/none.rb +76 -0
- data/lib/clouds/clouds/openstack.rb +30 -0
- data/lib/clouds/clouds/rackspace-ng.rb +54 -0
- data/lib/clouds/clouds/rackspace.rb +78 -0
- data/lib/clouds/clouds/softlayer.rb +91 -0
- data/lib/clouds/metadata_formatter.rb +108 -0
- data/lib/clouds/metadata_provider.rb +128 -0
- data/lib/clouds/metadata_source.rb +87 -0
- data/lib/clouds/metadata_sources/certificate_metadata_source.rb +207 -0
- data/lib/clouds/metadata_sources/config_drive_metadata_source.rb +129 -0
- data/lib/clouds/metadata_sources/file_metadata_source.rb +74 -0
- data/lib/clouds/metadata_sources/http_metadata_source.rb +277 -0
- data/lib/clouds/metadata_sources/selective_metadata_source.rb +122 -0
- data/lib/clouds/metadata_tree_climber.rb +144 -0
- data/lib/clouds/metadata_writer.rb +155 -0
- data/lib/clouds/metadata_writers/dictionary_metadata_writer.rb +72 -0
- data/lib/clouds/metadata_writers/ruby_metadata_writer.rb +76 -0
- data/lib/clouds/metadata_writers/shell_metadata_writer.rb +121 -0
- data/lib/clouds/register_clouds.rb +34 -0
- data/lib/clouds.rb +32 -0
- data/lib/gem_dependencies.rb +83 -0
- data/lib/git_hooks/commit-msg.rb +7 -0
- data/lib/instance/agent_config.rb +168 -0
- data/lib/instance/agent_watcher.rb +233 -0
- data/lib/instance/audit_cook_stub.rb +104 -0
- data/lib/instance/audit_proxy.rb +247 -0
- data/lib/instance/bundle_queue.rb +104 -0
- data/lib/instance/cook/agent_connection.rb +109 -0
- data/lib/instance/cook/audit_logger.rb +165 -0
- data/lib/instance/cook/audit_stub.rb +142 -0
- data/lib/instance/cook/ca-bundle.crt +2794 -0
- data/lib/instance/cook/chef_state.rb +211 -0
- data/lib/instance/cook/cook.rb +306 -0
- data/lib/instance/cook/cook_state.rb +298 -0
- data/lib/instance/cook/cookbook_path_mapping.rb +66 -0
- data/lib/instance/cook/cookbook_repo_retriever.rb +190 -0
- data/lib/instance/cook/executable_sequence.rb +765 -0
- data/lib/instance/cook/external_parameter_gatherer.rb +190 -0
- data/lib/instance/cook/repose_downloader.rb +349 -0
- data/lib/instance/cook/shutdown_request_proxy.rb +121 -0
- data/lib/instance/cook.rb +41 -0
- data/lib/instance/downloader.rb +208 -0
- data/lib/instance/duplicable.rb +67 -0
- data/lib/instance/exceptions.rb +49 -0
- data/lib/instance/executable_sequence_proxy.rb +278 -0
- data/lib/instance/instance_commands.rb +577 -0
- data/lib/instance/instance_state.rb +633 -0
- data/lib/instance/json_utilities.rb +102 -0
- data/lib/instance/login_manager.rb +533 -0
- data/lib/instance/login_user_manager.rb +522 -0
- data/lib/instance/message_encoder.rb +118 -0
- data/lib/instance/multi_thread_bundle_queue.rb +232 -0
- data/lib/instance/operation_context.rb +60 -0
- data/lib/instance/options_bag.rb +65 -0
- data/lib/instance/payload_formatter.rb +46 -0
- data/lib/instance/policy.rb +53 -0
- data/lib/instance/policy_audit.rb +100 -0
- data/lib/instance/policy_manager.rb +146 -0
- data/lib/instance/reenroll_manager.rb +104 -0
- data/lib/instance/right_scripts_cookbook.rb +181 -0
- data/lib/instance/shutdown_request.rb +221 -0
- data/lib/instance/single_thread_bundle_queue.rb +189 -0
- data/lib/instance/volume_management.rb +450 -0
- data/lib/instance.rb +50 -0
- data/lib/repo_conf_generators/apt_conf_generators.rb +106 -0
- data/lib/repo_conf_generators/gem_conf_generators.rb +80 -0
- data/lib/repo_conf_generators/rightscale_conf_generators.rb +254 -0
- data/lib/repo_conf_generators/rightscale_key.pub +17 -0
- data/lib/repo_conf_generators/yum_conf_generators.rb +225 -0
- data/lib/repo_conf_generators.rb +30 -0
- data/lib/run_shell.rb +28 -0
- data/scripts/agent_checker.rb +571 -0
- data/scripts/agent_controller.rb +247 -0
- data/scripts/agent_deployer.rb +148 -0
- data/scripts/bundle_runner.rb +336 -0
- data/scripts/cloud_controller.rb +176 -0
- data/scripts/log_level_manager.rb +142 -0
- data/scripts/ohai_runner.rb +33 -0
- data/scripts/reenroller.rb +193 -0
- data/scripts/server_importer.rb +293 -0
- data/scripts/shutdown_client.rb +183 -0
- data/scripts/system_configurator.rb +367 -0
- data/scripts/tagger.rb +381 -0
- data/scripts/thunker.rb +356 -0
- metadata +418 -0
@@ -0,0 +1,208 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009-2011 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require 'fileutils'
|
24
|
+
|
25
|
+
module RightScale
|
26
|
+
|
27
|
+
# Abstract download capabilities
|
28
|
+
class Downloader
|
29
|
+
|
30
|
+
DEFAULT_MAX_DOWNLOAD_RETRIES = 10
|
31
|
+
|
32
|
+
# Initialize downloader with given retry period
|
33
|
+
# When using backoff algorithm the retry period specifies the initial value, the value then gets
|
34
|
+
# incremented after each retry exponentially until it reaches the specified maximum retry period
|
35
|
+
#
|
36
|
+
# === Parameters
|
37
|
+
# retry_period(Integer):: Retry period in seconds - defaults to 10 seconds
|
38
|
+
# use_backoff(Boolean):: Whether download should use a backoff algorithm to space retries - defaults to true
|
39
|
+
# max_retry_period(Integer):: Maximum retry period in seconds, only meaningful when using backoff algorithm -
|
40
|
+
# defaults to 5 minutes
|
41
|
+
def initialize(retry_period = 10, use_backoff = true, max_retry_period = 5 * 60)
|
42
|
+
@retry_period = retry_period
|
43
|
+
@use_backoff = use_backoff
|
44
|
+
@max_retry_period = max_retry_period if use_backoff
|
45
|
+
platform = RightScale::Platform
|
46
|
+
@found_curl = platform.filesystem.has_executable_in_path('curl')
|
47
|
+
end
|
48
|
+
|
49
|
+
# (Integer) Retry period in seconds
|
50
|
+
attr_accessor :retry_period
|
51
|
+
|
52
|
+
# (Boolean) Whether download should use a backoff algorithm to space retries
|
53
|
+
attr_accessor :use_backoff
|
54
|
+
|
55
|
+
# (Integer) Maximum retry period in seconds, only meaningful when using backoff algorithm
|
56
|
+
attr_accessor :max_retry_period
|
57
|
+
|
58
|
+
# (Integer) Size in bytes of last successful download (nil if none)
|
59
|
+
attr_reader :size
|
60
|
+
|
61
|
+
# (Integer) Speed in bytes/seconds of last successful download (nil if none)
|
62
|
+
attr_reader :speed
|
63
|
+
|
64
|
+
# Error message associated with last failure (nil if none)
|
65
|
+
#
|
66
|
+
# === Return
|
67
|
+
# error(String):: Error message
|
68
|
+
# nil:: No error occured during last download
|
69
|
+
def error
|
70
|
+
error = (@errors.nil? || @errors.empty?) ? nil : @errors.join("\n")
|
71
|
+
end
|
72
|
+
|
73
|
+
# Was last download successful?
|
74
|
+
#
|
75
|
+
# === Return
|
76
|
+
# true:: If last download was successful or there was no download yet
|
77
|
+
# false:: Otherwise
|
78
|
+
def successful?
|
79
|
+
error.nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
# Download file synchronously and report on success, download size and download speed.
|
83
|
+
# Use successful, size and speed to query about last download.
|
84
|
+
# If last download failed, use error to retrieve error message.
|
85
|
+
# Requires 'curl' to be available on PATH.
|
86
|
+
#
|
87
|
+
# === Parameters
|
88
|
+
# url(String):: URL to downloaded file
|
89
|
+
# dest(String):: Path where file should be saved on disk
|
90
|
+
# username(String):: Optional HTTP basic authentication username
|
91
|
+
# password(String):: Optional HTTP basic authentication password
|
92
|
+
# max_retries(Integer):: Maximum number of retries - defaults to DEFAULT_MAX_DOWNLOAD_RETRIES
|
93
|
+
#
|
94
|
+
# === Block
|
95
|
+
# Call (optional) passed in block after each unsuccessful download attempt.
|
96
|
+
# Block must accept one argument corresponding to the last returned http code.
|
97
|
+
#
|
98
|
+
# === Return
|
99
|
+
# true:: Download was successful
|
100
|
+
# false:: Download failed
|
101
|
+
def download(url, dest, username=nil, password=nil, max_retries=DEFAULT_MAX_DOWNLOAD_RETRIES)
|
102
|
+
@errors = []
|
103
|
+
retry_count = error_code = 0
|
104
|
+
success = false
|
105
|
+
reset_wait_time_span
|
106
|
+
|
107
|
+
@errors << 'curl is not installed' unless @found_curl
|
108
|
+
|
109
|
+
@errors << "destination file '#{dest}' is a directory" if File.directory?(dest)
|
110
|
+
begin
|
111
|
+
FileUtils.mkdir_p(File.dirname(dest)) unless File.directory?(File.dirname(dest))
|
112
|
+
rescue Exception => e
|
113
|
+
@errors << e.message
|
114
|
+
end
|
115
|
+
|
116
|
+
return false unless @errors.empty?
|
117
|
+
|
118
|
+
# format curl command and redirect stderr away.
|
119
|
+
#
|
120
|
+
# note: ensure we use double-quotes (") to surround arguments on command
|
121
|
+
# line because single-quotes (') are literals in windows.
|
122
|
+
platform = RightScale::Platform
|
123
|
+
user_opt = username && password ? "--user \"#{username}:#{password}\"" : ""
|
124
|
+
dest = platform.filesystem.long_path_to_short_path(dest)
|
125
|
+
cmd = "curl --fail --silent --show-error --insecure --location --connect-timeout 300 --max-time 3600 --write-out \"%{http_code} %{size_download} %{speed_download}\" #{user_opt} --output \"#{dest}\" \"#{url}\""
|
126
|
+
cmd = platform.shell.format_redirect_stderr(cmd)
|
127
|
+
begin
|
128
|
+
out = `#{cmd}`
|
129
|
+
out = out.split
|
130
|
+
success = $?.success? && out.size == 3
|
131
|
+
if success
|
132
|
+
@size = out[1].to_i
|
133
|
+
@speed = out[2].to_i
|
134
|
+
@last_url = url
|
135
|
+
return true
|
136
|
+
else
|
137
|
+
retry_count += 1
|
138
|
+
error_code = out[0].to_i
|
139
|
+
yield error_code if block_given?
|
140
|
+
sleep wait_time_span
|
141
|
+
end
|
142
|
+
end until success || retry_count >= max_retries
|
143
|
+
unless success
|
144
|
+
@errors << "#{retry_count} download attempts failed, last HTTP response code was #{error_code}"
|
145
|
+
return false
|
146
|
+
end
|
147
|
+
true
|
148
|
+
end
|
149
|
+
|
150
|
+
# Message summarizing last successful download details
|
151
|
+
#
|
152
|
+
# === Return
|
153
|
+
# details(String):: Message with last url, download size and speed
|
154
|
+
def details
|
155
|
+
"Downloaded #{sanitize_uri(@last_url)} (#{ scale(size.to_i).join(' ') }) at #{ scale(speed.to_i).join(' ') }/s"
|
156
|
+
end
|
157
|
+
|
158
|
+
protected
|
159
|
+
|
160
|
+
# Calculate wait time span before next download retry, takes into account retry period and whether backoff
|
161
|
+
# algorithm should be used
|
162
|
+
#
|
163
|
+
# === Return
|
164
|
+
# time_span(Integer):: Number of seconds algorithm should wait before proceeding with next download attempt
|
165
|
+
def wait_time_span
|
166
|
+
return @retry_period unless @use_backoff
|
167
|
+
time_span = [ 2 ** @iteration * @retry_period, @max_retry_period ].min
|
168
|
+
@iteration += 1
|
169
|
+
time_span
|
170
|
+
end
|
171
|
+
|
172
|
+
# Reset backoff algorithm
|
173
|
+
#
|
174
|
+
# === Return
|
175
|
+
# true:: Always return true
|
176
|
+
def reset_wait_time_span
|
177
|
+
@iteration = 0
|
178
|
+
true
|
179
|
+
end
|
180
|
+
|
181
|
+
# Return scale and scaled value from given argument
|
182
|
+
# Scale can be B, KB, MB or GB
|
183
|
+
#
|
184
|
+
# === Return
|
185
|
+
# scaled(Array):: First element is scaled value, second element is scale ('B', 'KB', 'MB' or 'GB')
|
186
|
+
def scale(value)
|
187
|
+
scaled = case value
|
188
|
+
when 0..1023
|
189
|
+
[value, 'B']
|
190
|
+
when 1024..1024**2 - 1
|
191
|
+
[value / 1024, 'KB']
|
192
|
+
when 1024^2..1024**3 - 1
|
193
|
+
[value / 1024**2, 'MB']
|
194
|
+
else
|
195
|
+
[value / 1024**3, 'GB']
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def sanitize_uri(uri)
|
200
|
+
begin
|
201
|
+
uri = URI.parse(uri)
|
202
|
+
return "#{uri.scheme}://#{uri.host}#{uri.path}"
|
203
|
+
rescue Exception => e
|
204
|
+
return "file"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009-2011 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
# Code taken from RAILS which allows checking whether '.dup' can be called
|
24
|
+
# on an arbitrary object
|
25
|
+
class Object
|
26
|
+
# Can you safely .dup this object?
|
27
|
+
# False for nil, false, true, symbols, numbers, and class objects; true otherwise.
|
28
|
+
def duplicable?
|
29
|
+
true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class NilClass #:nodoc:
|
34
|
+
def duplicable?
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class FalseClass #:nodoc:
|
40
|
+
def duplicable?
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class TrueClass #:nodoc:
|
46
|
+
def duplicable?
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Symbol #:nodoc:
|
52
|
+
def duplicable?
|
53
|
+
false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Numeric #:nodoc:
|
58
|
+
def duplicable?
|
59
|
+
false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class Class #:nodoc:
|
64
|
+
def duplicable?
|
65
|
+
false
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009-2011 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
begin
|
24
|
+
require 'chef/exceptions'
|
25
|
+
rescue LoadError => e
|
26
|
+
# Make sure we're dealing with a legitimate missing-file LoadError
|
27
|
+
raise e unless e.message =~ /^no such file to load/
|
28
|
+
|
29
|
+
# Do not require the chef gem to be installed just to load this code
|
30
|
+
module Chef
|
31
|
+
class Exceptions
|
32
|
+
class Exec < RuntimeError; end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module RightScale
|
38
|
+
# Extend the set of RightScale extensions
|
39
|
+
class Exceptions
|
40
|
+
class WrongState < RuntimeError; end
|
41
|
+
class Exec < Chef::Exceptions::Exec
|
42
|
+
def initialize(msg, cwd=nil)
|
43
|
+
super(msg)
|
44
|
+
@path = cwd
|
45
|
+
end
|
46
|
+
attr_reader :path # Path where command was run
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009-2011 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require 'right_popen'
|
24
|
+
|
25
|
+
module RightScale
|
26
|
+
|
27
|
+
# Bundle sequence proxy, create child process to execute bundle
|
28
|
+
# Use right_popen gem to control child process asynchronously
|
29
|
+
class ExecutableSequenceProxy
|
30
|
+
DEFAULT_OPTIONS = {
|
31
|
+
:tag_query_timeout => 120
|
32
|
+
}
|
33
|
+
|
34
|
+
include EM::Deferrable
|
35
|
+
|
36
|
+
# Wait up to 20 seconds to process pending audits after child process exited
|
37
|
+
AUDIT_CLOSE_TIMEOUT = 20
|
38
|
+
|
39
|
+
# (Hash) Inputs patch to be forwarded to core after each converge
|
40
|
+
attr_accessor :inputs_patch
|
41
|
+
|
42
|
+
# (::RightScale::OperationContext) operation context containing bundle
|
43
|
+
attr_reader :context
|
44
|
+
|
45
|
+
# PID for created process or nil
|
46
|
+
attr_reader :pid
|
47
|
+
|
48
|
+
# Execution thread name or default.
|
49
|
+
attr_reader :thread_name
|
50
|
+
|
51
|
+
# Initialize sequence
|
52
|
+
#
|
53
|
+
# === Parameters
|
54
|
+
# context(RightScale::OperationContext):: Bundle to be run and associated audit
|
55
|
+
#
|
56
|
+
# === Options
|
57
|
+
# :pid_callback(Proc):: proc that will be called, passing self, when the PID of the child process becomes known
|
58
|
+
# :tag_query_timeout(Proc):: default 120 -- how many seconds to wait for the agent tag query to complete, before giving up and continuing
|
59
|
+
def initialize(context, options = {})
|
60
|
+
options = DEFAULT_OPTIONS.merge(options)
|
61
|
+
@context = context
|
62
|
+
@thread_name = get_thread_name_from_context(context)
|
63
|
+
@pid_callback = options[:pid_callback]
|
64
|
+
@tag_query_timeout = options[:tag_query_timeout]
|
65
|
+
|
66
|
+
AuditCookStub.instance.setup_audit_forwarding(@thread_name, context.audit)
|
67
|
+
AuditCookStub.instance.on_close(@thread_name) { @audit_closed = true; check_done }
|
68
|
+
end
|
69
|
+
|
70
|
+
# FIX: thread_name should never be nil from the core in future, but
|
71
|
+
# temporarily we must supply the default thread_name before if nil. in
|
72
|
+
# future we should fail execution when thread_name is reliably present and
|
73
|
+
# for any reason does not match ::RightScale::AgentConfig.valid_thread_name
|
74
|
+
# see also ExecutableSequenceProxy#initialize
|
75
|
+
#
|
76
|
+
# === Parameters
|
77
|
+
# bundle(OperationalContext):: An operational context
|
78
|
+
#
|
79
|
+
# === Return
|
80
|
+
# result(String):: Thread name of this context
|
81
|
+
def get_thread_name_from_context(context)
|
82
|
+
thread_name = nil
|
83
|
+
thread_name = context.thread_name if context.respond_to?(:thread_name)
|
84
|
+
Log.warn("Encountered a nil thread name unexpectedly, defaulting to '#{RightScale::AgentConfig.default_thread_name}'") unless thread_name
|
85
|
+
thread_name ||= RightScale::AgentConfig.default_thread_name
|
86
|
+
unless thread_name =~ RightScale::AgentConfig.valid_thread_name
|
87
|
+
raise ArgumentError, "Invalid thread name #{thread_name.inspect}"
|
88
|
+
end
|
89
|
+
thread_name
|
90
|
+
end
|
91
|
+
|
92
|
+
# Run given executable bundle
|
93
|
+
# Asynchronous, set deferrable object's disposition
|
94
|
+
#
|
95
|
+
# === Return
|
96
|
+
# true:: Always return true
|
97
|
+
def run
|
98
|
+
@succeeded = true
|
99
|
+
|
100
|
+
@context.audit.create_new_section('Querying tags')
|
101
|
+
|
102
|
+
# update CookState with the latest instance before launching Cook
|
103
|
+
RightScale::AgentTagManager.instance.tags(:timeout=>@tag_query_timeout) do |tags|
|
104
|
+
if tags.is_a?(String)
|
105
|
+
# AgentTagManager could give us a String (error message)
|
106
|
+
Log.error("Failed to query tags before running executable sequence: #{tags}")
|
107
|
+
|
108
|
+
@context.audit.append_error('Could not discover tags due to an error or timeout.')
|
109
|
+
else
|
110
|
+
# or, it could give us anything else -- generally an array) -- which indicates success
|
111
|
+
CookState.update(InstanceState, :startup_tags=>tags)
|
112
|
+
|
113
|
+
if tags.empty?
|
114
|
+
@context.audit.append_info('No tags discovered.')
|
115
|
+
else
|
116
|
+
@context.audit.append_info("Tags discovered: '#{tags.join("', '")}'")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
input_text = "#{MessageEncoder.for_agent(InstanceState.identity).encode(@context.payload)}\n"
|
121
|
+
|
122
|
+
# TEAL FIX: we have an issue with the Windows EM implementation not
|
123
|
+
# allowing both sockets and named pipes to share the same file/socket
|
124
|
+
# id. sending the input on the command line is a temporary workaround.
|
125
|
+
platform = RightScale::Platform
|
126
|
+
if platform.windows?
|
127
|
+
input_path = File.normalize_path(File.join(platform.filesystem.temp_dir, "rs_executable_sequence#{@thread_name}.txt"))
|
128
|
+
File.open(input_path, "w") { |f| f.write(input_text) }
|
129
|
+
input_text = nil
|
130
|
+
cmd_exe_path = File.normalize_path(ENV['ComSpec']).gsub("/", "\\")
|
131
|
+
ruby_exe_path = File.normalize_path(AgentConfig.ruby_cmd).gsub("/", "\\")
|
132
|
+
input_path = input_path.gsub("/", "\\")
|
133
|
+
cmd = "#{cmd_exe_path} /C type \"#{input_path}\" | #{ruby_exe_path} #{cook_path_and_arguments}"
|
134
|
+
else
|
135
|
+
# WARNING - always ensure cmd is a String, never an Array of command parts.
|
136
|
+
#
|
137
|
+
# right_popen handles single-String arguments using "sh -c #{cmd}" which ensures
|
138
|
+
# we are invoked through a shell which will parse shell config files and ensure that
|
139
|
+
# changes to system PATH, etc are freshened on every converge.
|
140
|
+
#
|
141
|
+
# If we pass cmd as an Array, right_popen uses the Array form of exec without an
|
142
|
+
# intermediate shell, and system config changes will not be picked up.
|
143
|
+
cmd = "#{AgentConfig.ruby_cmd} #{cook_path_and_arguments}"
|
144
|
+
end
|
145
|
+
|
146
|
+
EM.next_tick do
|
147
|
+
# prepare env vars for child process.
|
148
|
+
environment = {
|
149
|
+
::RightScale::OptionsBag::OPTIONS_ENV =>
|
150
|
+
::ENV[::RightScale::OptionsBag::OPTIONS_ENV]
|
151
|
+
}
|
152
|
+
if @context.decommission?
|
153
|
+
environment['RS_DECOM_REASON'] = @context.decommission_type
|
154
|
+
end
|
155
|
+
|
156
|
+
# spawn
|
157
|
+
RightScale::RightPopen.popen3_async(
|
158
|
+
cmd,
|
159
|
+
:input => input_text,
|
160
|
+
:target => self,
|
161
|
+
:environment => environment,
|
162
|
+
:stdout_handler => :on_read_stdout,
|
163
|
+
:stderr_handler => :on_read_stderr,
|
164
|
+
:pid_handler => :on_pid,
|
165
|
+
:exit_handler => :on_exit)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
protected
|
171
|
+
|
172
|
+
# Path to 'cook_runner' ruby script
|
173
|
+
#
|
174
|
+
# === Return
|
175
|
+
# path(String):: Path to ruby script used to run Chef
|
176
|
+
def cook_path
|
177
|
+
relative_path = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'cook_runner')
|
178
|
+
return File.normalize_path(relative_path)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Command line fragment for the cook script path and any arguments.
|
182
|
+
#
|
183
|
+
# === Return
|
184
|
+
# path_and_arguments(String):: Cook path plus any arguments properly quoted.
|
185
|
+
def cook_path_and_arguments
|
186
|
+
return "\"#{cook_path}\""
|
187
|
+
end
|
188
|
+
|
189
|
+
# Handle cook standard output, should not get called
|
190
|
+
#
|
191
|
+
# === Parameters
|
192
|
+
# data(String):: Standard output content
|
193
|
+
#
|
194
|
+
# === Return
|
195
|
+
# true:: Always return true
|
196
|
+
def on_read_stdout(data)
|
197
|
+
Log.error("Unexpected output from execution: #{data.inspect}")
|
198
|
+
end
|
199
|
+
|
200
|
+
# Handle cook error output
|
201
|
+
#
|
202
|
+
# === Parameters
|
203
|
+
# data(String):: Error output content
|
204
|
+
#
|
205
|
+
# === Return
|
206
|
+
# true:: Always return true
|
207
|
+
def on_read_stderr(data)
|
208
|
+
@context.audit.append_info(data)
|
209
|
+
end
|
210
|
+
|
211
|
+
# Receives the pid for the created process.
|
212
|
+
def on_pid(pid)
|
213
|
+
@pid = pid
|
214
|
+
@pid_callback.call(self) if @pid_callback
|
215
|
+
end
|
216
|
+
|
217
|
+
# Handle runner process exited event
|
218
|
+
#
|
219
|
+
# === Parameters
|
220
|
+
# status(Process::Status):: Exit status
|
221
|
+
#
|
222
|
+
# === Return
|
223
|
+
# true:: Always return true
|
224
|
+
def on_exit(status)
|
225
|
+
@exit_status = status
|
226
|
+
check_done
|
227
|
+
end
|
228
|
+
|
229
|
+
# Check whether child process exited *and* all audits were processed
|
230
|
+
# Do not proceed until both these conditions are true
|
231
|
+
# If the child process exited start a timer so that if there was a failure
|
232
|
+
# and the child process was not able to properly close the auditing we will
|
233
|
+
# still proceed and be able to handle other scripts/recipes
|
234
|
+
#
|
235
|
+
# Note: success and failure reports are handled by the cook process for normal
|
236
|
+
# scenarios. We only handle cook process execution failures here.
|
237
|
+
#
|
238
|
+
# === Return
|
239
|
+
# true:: Always return true
|
240
|
+
def check_done
|
241
|
+
if @exit_status && @audit_closed
|
242
|
+
if @audit_close_timeout
|
243
|
+
@audit_close_timeout.cancel
|
244
|
+
@audit_close_timeout = nil
|
245
|
+
end
|
246
|
+
if !@exit_status.success?
|
247
|
+
RightScale::PolicyManager.fail(@context.payload)
|
248
|
+
report_failure("Subprocess #{SubprocessFormatting.reason(@exit_status)}")
|
249
|
+
else
|
250
|
+
@context.succeeded = true
|
251
|
+
RightScale::PolicyManager.success(@context.payload)
|
252
|
+
succeed
|
253
|
+
end
|
254
|
+
elsif @exit_status
|
255
|
+
@audit_close_timeout = EM::Timer.new(AUDIT_CLOSE_TIMEOUT) { AuditCookStub.instance.close(@thread_name) }
|
256
|
+
end
|
257
|
+
true
|
258
|
+
end
|
259
|
+
|
260
|
+
# Report cook process execution failure
|
261
|
+
#
|
262
|
+
# === Parameters
|
263
|
+
# title(String):: Title used to update audit status
|
264
|
+
# msg(String):: Optional, extended failure message
|
265
|
+
#
|
266
|
+
# === Return
|
267
|
+
# true:: Always return true
|
268
|
+
def report_failure(title, msg=nil)
|
269
|
+
@context.audit.append_error(title, :category => RightScale::EventCategories::CATEGORY_ERROR)
|
270
|
+
@context.audit.append_error(msg) unless msg.nil?
|
271
|
+
@context.succeeded = false
|
272
|
+
fail
|
273
|
+
true
|
274
|
+
end
|
275
|
+
|
276
|
+
end
|
277
|
+
|
278
|
+
end
|