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.
Files changed (199) hide show
  1. data/actors/agent_manager.rb +88 -0
  2. data/actors/instance_scheduler.rb +321 -0
  3. data/actors/instance_services.rb +64 -0
  4. data/actors/instance_setup.rb +567 -0
  5. data/bin/cloud +25 -0
  6. data/bin/cook_runner +44 -0
  7. data/bin/deploy +120 -0
  8. data/bin/enroll +385 -0
  9. data/bin/rad +32 -0
  10. data/bin/rchk +29 -0
  11. data/bin/rnac +39 -0
  12. data/bin/rs_connect +33 -0
  13. data/bin/rs_log_level +31 -0
  14. data/bin/rs_ohai +28 -0
  15. data/bin/rs_reenroll +31 -0
  16. data/bin/rs_run_recipe +34 -0
  17. data/bin/rs_run_right_script +34 -0
  18. data/bin/rs_shutdown +33 -0
  19. data/bin/rs_tag +33 -0
  20. data/bin/rs_thunk +33 -0
  21. data/bin/rstat +31 -0
  22. data/bin/system +16 -0
  23. data/ext/Rakefile +18 -0
  24. data/init/config.yml +5 -0
  25. data/init/init.rb +79 -0
  26. data/lib/chef/ohai_setup.rb +51 -0
  27. data/lib/chef/plugins/cloud.rb +91 -0
  28. data/lib/chef/plugins/cloudstack.rb +23 -0
  29. data/lib/chef/plugins/ec2.rb +23 -0
  30. data/lib/chef/plugins/linux/block_device2.rb +24 -0
  31. data/lib/chef/plugins/rackspace.rb +23 -0
  32. data/lib/chef/plugins/rightscale.rb +125 -0
  33. data/lib/chef/plugins/windows/network.rb +114 -0
  34. data/lib/chef/plugins.rb +74 -0
  35. data/lib/chef/providers/dns_dnsmadeeasy_provider.rb +81 -0
  36. data/lib/chef/providers/dns_resource.rb +100 -0
  37. data/lib/chef/providers/executable_schedule_provider.rb +70 -0
  38. data/lib/chef/providers/executable_schedule_resource.rb +144 -0
  39. data/lib/chef/providers/remote_recipe_provider.rb +86 -0
  40. data/lib/chef/providers/remote_recipe_resource.rb +101 -0
  41. data/lib/chef/providers/right_link_tag_provider.rb +73 -0
  42. data/lib/chef/providers/right_link_tag_resource.rb +59 -0
  43. data/lib/chef/providers/right_script_provider.rb +190 -0
  44. data/lib/chef/providers/right_script_resource.rb +113 -0
  45. data/lib/chef/providers/rs_shutdown_provider.rb +75 -0
  46. data/lib/chef/providers/rs_shutdown_resource.rb +55 -0
  47. data/lib/chef/providers/server_collection_provider.rb +66 -0
  48. data/lib/chef/providers/server_collection_resource.rb +93 -0
  49. data/lib/chef/providers/windows/powershell_provider.rb +151 -0
  50. data/lib/chef/providers/windows/powershell_resource.rb +111 -0
  51. data/lib/chef/providers/windows/unsupported_provider.rb +51 -0
  52. data/lib/chef/right_providers.rb +55 -0
  53. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ChefNodeCmdlet.csproj +104 -0
  54. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ChefNodeCmdlet.dll-Help.xml +141 -0
  55. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/Exceptions.cs +182 -0
  56. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetChefNodeCommand.cs +58 -0
  57. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetChefNodeRequest.cs +46 -0
  58. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetChefNodeResponse.cs +45 -0
  59. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetCurrentResourceCommand.cs +58 -0
  60. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetCurrentResourceRequest.cs +46 -0
  61. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetCurrentResourceResponse.cs +45 -0
  62. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNewResourceCommand.cs +58 -0
  63. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNewResourceRequest.cs +46 -0
  64. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNewResourceResponse.cs +45 -0
  65. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNextActionCommand.cs +178 -0
  66. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNextActionRequest.cs +67 -0
  67. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNextActionResponse.cs +58 -0
  68. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNodeValueCommandBase.cs +142 -0
  69. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNodeValueRequestBase.cs +64 -0
  70. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNodeValueResponseBase.cs +69 -0
  71. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/JsonTransport.cs +110 -0
  72. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/PipeClient.cs +158 -0
  73. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/PipeServer.cs +142 -0
  74. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/Properties/AssemblyInfo.cs +16 -0
  75. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ProtocolConstants.cs +55 -0
  76. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ProtocolUtilities.cs +77 -0
  77. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ReadMe.txt +53 -0
  78. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetChefNodeCommand.cs +59 -0
  79. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetChefNodeRequest.cs +46 -0
  80. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetChefNodeResponse.cs +58 -0
  81. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetCurrentResourceCommand.cs +59 -0
  82. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetCurrentResourceRequest.cs +46 -0
  83. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetCurrentResourceResponse.cs +40 -0
  84. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNewResourceCommand.cs +59 -0
  85. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNewResourceRequest.cs +46 -0
  86. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNewResourceResponse.cs +40 -0
  87. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNodeValueCommandBase.cs +293 -0
  88. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNodeValueRequestBase.cs +75 -0
  89. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNodeValueResponseBase.cs +45 -0
  90. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/Transport.cs +91 -0
  91. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet.sln +35 -0
  92. data/lib/chef/windows/ChefNodeCmdlet/TestChefNodeCmdlet/Program.cs +374 -0
  93. data/lib/chef/windows/ChefNodeCmdlet/TestChefNodeCmdlet/Properties/AssemblyInfo.cs +16 -0
  94. data/lib/chef/windows/ChefNodeCmdlet/TestChefNodeCmdlet/TestChefNodeCmdlet.csproj +65 -0
  95. data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/Program.cs +136 -0
  96. data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/Properties/AssemblyInfo.cs +36 -0
  97. data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/ReadMe.txt +46 -0
  98. data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/TestNextActionCmdlet.csproj +68 -0
  99. data/lib/chef/windows/bin/Newtonsoft.Json.dll +0 -0
  100. data/lib/chef/windows/chef_node_server.rb +463 -0
  101. data/lib/chef/windows/dynamic_powershell_provider.rb +296 -0
  102. data/lib/chef/windows/pipe_server.rb +283 -0
  103. data/lib/chef/windows/powershell_host.rb +285 -0
  104. data/lib/chef/windows/powershell_pipe_server.rb +136 -0
  105. data/lib/chef/windows/powershell_provider_base.rb +92 -0
  106. data/lib/chef/windows/scripts/run_loop.ps1 +105 -0
  107. data/lib/clouds/cloud.rb +557 -0
  108. data/lib/clouds/cloud_factory.rb +250 -0
  109. data/lib/clouds/cloud_utilities.rb +244 -0
  110. data/lib/clouds/clouds/azure.rb +106 -0
  111. data/lib/clouds/clouds/cloudstack.rb +114 -0
  112. data/lib/clouds/clouds/ec2.rb +113 -0
  113. data/lib/clouds/clouds/eucalyptus.rb +46 -0
  114. data/lib/clouds/clouds/google.rb +102 -0
  115. data/lib/clouds/clouds/none.rb +76 -0
  116. data/lib/clouds/clouds/openstack.rb +30 -0
  117. data/lib/clouds/clouds/rackspace-ng.rb +54 -0
  118. data/lib/clouds/clouds/rackspace.rb +78 -0
  119. data/lib/clouds/clouds/softlayer.rb +91 -0
  120. data/lib/clouds/metadata_formatter.rb +108 -0
  121. data/lib/clouds/metadata_provider.rb +128 -0
  122. data/lib/clouds/metadata_source.rb +87 -0
  123. data/lib/clouds/metadata_sources/certificate_metadata_source.rb +207 -0
  124. data/lib/clouds/metadata_sources/config_drive_metadata_source.rb +129 -0
  125. data/lib/clouds/metadata_sources/file_metadata_source.rb +74 -0
  126. data/lib/clouds/metadata_sources/http_metadata_source.rb +277 -0
  127. data/lib/clouds/metadata_sources/selective_metadata_source.rb +122 -0
  128. data/lib/clouds/metadata_tree_climber.rb +144 -0
  129. data/lib/clouds/metadata_writer.rb +155 -0
  130. data/lib/clouds/metadata_writers/dictionary_metadata_writer.rb +72 -0
  131. data/lib/clouds/metadata_writers/ruby_metadata_writer.rb +76 -0
  132. data/lib/clouds/metadata_writers/shell_metadata_writer.rb +121 -0
  133. data/lib/clouds/register_clouds.rb +34 -0
  134. data/lib/clouds.rb +32 -0
  135. data/lib/gem_dependencies.rb +83 -0
  136. data/lib/git_hooks/commit-msg.rb +7 -0
  137. data/lib/instance/agent_config.rb +168 -0
  138. data/lib/instance/agent_watcher.rb +233 -0
  139. data/lib/instance/audit_cook_stub.rb +104 -0
  140. data/lib/instance/audit_proxy.rb +247 -0
  141. data/lib/instance/bundle_queue.rb +104 -0
  142. data/lib/instance/cook/agent_connection.rb +109 -0
  143. data/lib/instance/cook/audit_logger.rb +165 -0
  144. data/lib/instance/cook/audit_stub.rb +142 -0
  145. data/lib/instance/cook/ca-bundle.crt +2794 -0
  146. data/lib/instance/cook/chef_state.rb +211 -0
  147. data/lib/instance/cook/cook.rb +306 -0
  148. data/lib/instance/cook/cook_state.rb +298 -0
  149. data/lib/instance/cook/cookbook_path_mapping.rb +66 -0
  150. data/lib/instance/cook/cookbook_repo_retriever.rb +190 -0
  151. data/lib/instance/cook/executable_sequence.rb +765 -0
  152. data/lib/instance/cook/external_parameter_gatherer.rb +190 -0
  153. data/lib/instance/cook/repose_downloader.rb +349 -0
  154. data/lib/instance/cook/shutdown_request_proxy.rb +121 -0
  155. data/lib/instance/cook.rb +41 -0
  156. data/lib/instance/downloader.rb +208 -0
  157. data/lib/instance/duplicable.rb +67 -0
  158. data/lib/instance/exceptions.rb +49 -0
  159. data/lib/instance/executable_sequence_proxy.rb +278 -0
  160. data/lib/instance/instance_commands.rb +577 -0
  161. data/lib/instance/instance_state.rb +633 -0
  162. data/lib/instance/json_utilities.rb +102 -0
  163. data/lib/instance/login_manager.rb +533 -0
  164. data/lib/instance/login_user_manager.rb +522 -0
  165. data/lib/instance/message_encoder.rb +118 -0
  166. data/lib/instance/multi_thread_bundle_queue.rb +232 -0
  167. data/lib/instance/operation_context.rb +60 -0
  168. data/lib/instance/options_bag.rb +65 -0
  169. data/lib/instance/payload_formatter.rb +46 -0
  170. data/lib/instance/policy.rb +53 -0
  171. data/lib/instance/policy_audit.rb +100 -0
  172. data/lib/instance/policy_manager.rb +146 -0
  173. data/lib/instance/reenroll_manager.rb +104 -0
  174. data/lib/instance/right_scripts_cookbook.rb +181 -0
  175. data/lib/instance/shutdown_request.rb +221 -0
  176. data/lib/instance/single_thread_bundle_queue.rb +189 -0
  177. data/lib/instance/volume_management.rb +450 -0
  178. data/lib/instance.rb +50 -0
  179. data/lib/repo_conf_generators/apt_conf_generators.rb +106 -0
  180. data/lib/repo_conf_generators/gem_conf_generators.rb +80 -0
  181. data/lib/repo_conf_generators/rightscale_conf_generators.rb +254 -0
  182. data/lib/repo_conf_generators/rightscale_key.pub +17 -0
  183. data/lib/repo_conf_generators/yum_conf_generators.rb +225 -0
  184. data/lib/repo_conf_generators.rb +30 -0
  185. data/lib/run_shell.rb +28 -0
  186. data/scripts/agent_checker.rb +571 -0
  187. data/scripts/agent_controller.rb +247 -0
  188. data/scripts/agent_deployer.rb +148 -0
  189. data/scripts/bundle_runner.rb +336 -0
  190. data/scripts/cloud_controller.rb +176 -0
  191. data/scripts/log_level_manager.rb +142 -0
  192. data/scripts/ohai_runner.rb +33 -0
  193. data/scripts/reenroller.rb +193 -0
  194. data/scripts/server_importer.rb +293 -0
  195. data/scripts/shutdown_client.rb +183 -0
  196. data/scripts/system_configurator.rb +367 -0
  197. data/scripts/tagger.rb +381 -0
  198. data/scripts/thunker.rb +356 -0
  199. 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