right_link 5.9.0
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/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
|