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,83 @@
1
+ # Copyright (c) 2011 RightScale Inc
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # RVM pollutes the process environment with garbage that prevents us from activating sandboxed
23
+ # RubyGems correctly. Unpollute the environment so our built-in RubyGems can setup the variables
24
+ # appropriately for our own usage (and for installation of gems into the sandbox!)
25
+ ['GEM_HOME', 'GEM_PATH', 'IRBRC', 'MY_RUBY_HOME'].each { |key| ENV.delete(key) }
26
+
27
+ require 'rubygems'
28
+
29
+ # Note: can't use File#normalize_path (for Windows safety) yet because it's
30
+ # defined by right_agent and gems haven't been activated yet.
31
+ basedir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
32
+
33
+ Dir.chdir(basedir) do
34
+ if File.exist?('Gemfile')
35
+ # Development mode: activate Bundler gem, then let it setup our RubyGems
36
+ # environment for us -- but don't have it auto-require any gem files; we
37
+ # will do that ourselves.
38
+ require 'bundler'
39
+ Bundler.setup
40
+ else
41
+ # Release mode: use 'bare' RubyGems; assume that all gems were installed
42
+ # as system gems. Nothing to do here...
43
+ gem 'right_link'
44
+
45
+ gem 'eventmachine'
46
+
47
+ gem 'right_support'
48
+ gem 'right_amqp'
49
+ gem 'right_agent'
50
+ gem 'right_popen'
51
+ gem 'right_http_connection'
52
+ gem 'right_scraper'
53
+
54
+ gem 'ohai'
55
+ gem 'chef'
56
+
57
+ # Note: can't use RightScale::Platform because gem sources aren't loaded
58
+ if RUBY_PLATFORM =~ /mswin|mingw/
59
+ gem 'win32-api'
60
+ gem 'windows-api'
61
+ gem 'windows-pr'
62
+ gem 'win32-dir'
63
+ gem 'win32-eventlog'
64
+ gem 'ruby-wmi'
65
+ gem 'win32-process'
66
+ gem 'win32-pipe'
67
+ gem 'win32-open3'
68
+ gem 'win32-service'
69
+ end
70
+ end
71
+ end
72
+
73
+ # Make sure gem bin directories appear at the end of the PATH so our wrapper
74
+ # scripts (e.g. those installed to /usr/bin) get top billing *iff* a bin dir
75
+ # already appears on the PATH. Notice we choose regexp patterns that work under
76
+ # both Linux and Windows.
77
+ sep = (RUBY_PLATFORM =~ /mswin|mingw|dos/) ? ';' : ':'
78
+ version = RUBY_VERSION.split('.')[0..1].join('.')
79
+ subdir = /(ruby|gems)[\\\/]#{version}[\\\/]bin/
80
+ paths = ENV['PATH'].split(sep)
81
+ gem_bin = paths.select { |p| p =~ subdir }
82
+ paths.delete_if { |p| p =~ subdir }
83
+ ENV['PATH'] = (paths + gem_bin).join(sep)
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Disallow 'refs #' in right_link commits
4
+ if IO.read(ARGV[0]) =~ /^(refs #|Refs #)\d+ /
5
+ puts 'Private ticket number reference.'
6
+ exit 1
7
+ end
@@ -0,0 +1,168 @@
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 'rbconfig'
24
+
25
+ module RightScale
26
+
27
+ # Extend AgentConfig for instance agents
28
+ AgentConfig.module_eval do
29
+
30
+ # Path to RightScale files in parent directory of right_link
31
+ def self.parent_dir
32
+ File.dirname(File.normalize_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'right_link')))
33
+ end
34
+
35
+ # @return [Array] an appropriate sequence of root directories for configuring the RightLink agent
36
+ def self.right_link_root_dirs
37
+ # RightLink certs are written at enrollment time, and live in the
38
+ # 'certs' subdir of the RightLink agent state dir.
39
+ os_root_dir = File.join(AgentConfig.agent_state_dir)
40
+
41
+ # RightLink actors and the agent init directory are both packaged into the RightLink gem,
42
+ # as subdirectories of the gem base directory (siblings of 'lib' and 'bin' directories).
43
+ gem_root_dir = Gem.loaded_specs['right_link'].full_gem_path
44
+
45
+ [os_root_dir, gem_root_dir]
46
+ end
47
+
48
+ # Path to directory containing persistent RightLink agent state
49
+ def self.agent_state_dir
50
+ RightScale::Platform.filesystem.right_link_dynamic_state_dir
51
+ end
52
+
53
+ # Path to the file that contains the name of the cloud for this instance
54
+ def self.cloud_file_path
55
+ File.normalize_path(File.join(
56
+ RightScale::Platform.filesystem.right_scale_static_state_dir,
57
+ 'cloud'))
58
+ end
59
+
60
+ # Path to directory containing transient cloud-related state (metadata, userdata, etc)
61
+ def self.cloud_state_dir
62
+ @cloud_state_dir ||= File.join(RightScale::Platform.filesystem.spool_dir, 'cloud')
63
+ end
64
+
65
+ # Set path to directory containing transient cloud-related state (metadata, userdata, etc)
66
+ def self.cloud_state_dir=(dir)
67
+ @cloud_state_dir = dir
68
+ end
69
+
70
+ # Path to directory for caching instance data
71
+ def self.cache_dir
72
+ @cache_dir ||= File.join(RightScale::Platform.filesystem.cache_dir, 'rightscale')
73
+ end
74
+
75
+ # Set path to directory for caching instance data
76
+ def self.cache_dir=(dir)
77
+ @cache_dir = dir
78
+ end
79
+
80
+ # Path to directory for Ruby source code, e.g. cookbooks
81
+ def self.source_code_dir
82
+ @source_code_dir ||= File.join(RightScale::Platform.filesystem.source_code_dir, 'rightscale')
83
+ end
84
+
85
+ # Set path to directory for Ruby source code, e.g. cookbooks
86
+ def self.source_code_dir=(dir)
87
+ @source_code_dir = dir
88
+ end
89
+
90
+ # Path to downloaded cookbooks directory
91
+ def self.cookbook_download_dir
92
+ @cookbook_download_dir ||= File.join(cache_dir, 'cookbooks')
93
+ end
94
+
95
+ # Path to SCM repository checkouts that contain development cookbooks
96
+ def self.dev_cookbook_checkout_dir
97
+ @dev_cookbook_dir ||= File.join(source_code_dir, 'cookbooks')
98
+ end
99
+
100
+ # Path to RightScript recipes cookbook directory
101
+ def self.right_scripts_repo_dir
102
+ @right_scripts_repo_dir ||= File.join(cache_dir, 'right_scripts')
103
+ end
104
+
105
+ # Maximum number of times agent should retry installing packages
106
+ def self.max_packages_install_retries
107
+ 3
108
+ end
109
+
110
+ # Path to directory for sandbox if it exists
111
+ def self.ruby_dir
112
+ ( ENV['RS_RUBY_EXE'] && File.dirname(ENV['RS_RUBY_EXE']) ) ||
113
+ Config::CONFIG["bindir"]
114
+ end
115
+
116
+ # Ruby command
117
+ def self.ruby_cmd
118
+ # Allow test environment to specify a non-program files location for tools
119
+ ENV['RS_RUBY_EXE'] ||
120
+ File.join( ruby_dir,
121
+ Config::CONFIG["RUBY_INSTALL_NAME"] + Config::CONFIG["EXEEXT"] )
122
+ end
123
+
124
+ # Sandbox gem command
125
+ def self.gem_cmd
126
+ if RightScale::Platform.windows?
127
+ # Allow test environment to specify a non-program files location for tools
128
+ if ENV['RS_GEM']
129
+ ENV['RS_GEM']
130
+ elsif dir = ruby_dir
131
+ "\"#{ruby_cmd}\" \"#{File.join(dir, 'gem.exe')}\""
132
+ else
133
+ 'gem'
134
+ end
135
+ else
136
+ if dir = ruby_dir
137
+ File.join(dir, 'gem')
138
+ else
139
+ # Development setup
140
+ `which gem`.chomp
141
+ end
142
+ end
143
+ end
144
+
145
+ # Sandbox git command
146
+ def self.git_cmd
147
+ if RightScale::Platform.windows?
148
+ # Allow test environment to specify a non-program files location for tools
149
+ if ENV['RS_GIT_EXE']
150
+ ENV['RS_GIT_EXE']
151
+ elsif dir = ruby_dir
152
+ File.normalize_path(File.join(dir, '..', '..', 'bin', 'windows', 'git.cmd'))
153
+ else
154
+ 'git'
155
+ end
156
+ else
157
+ if dir = ruby_dir
158
+ File.join(dir, 'git')
159
+ else
160
+ # Development setup
161
+ `which git`.chomp
162
+ end
163
+ end
164
+ end
165
+
166
+ end # AgentConfig
167
+
168
+ end # RightScale
@@ -0,0 +1,233 @@
1
+ # === Synopsis:
2
+ # RightScale Agent Watcher
3
+ #
4
+ # Agent monitoring intelligence. Will watch a given list of agents for
5
+ # unexpected termination and react accordingly. This can be either simply
6
+ # logging to a given IO stream, restarting the agent or yielding to any
7
+ # arbitrary block passed in during initialization.
8
+ #
9
+ # Copyright (c) 2013 RightScale Inc
10
+ #
11
+ # Permission is hereby granted, free of charge, to any person obtaining
12
+ # a copy of this software and associated documentation files (the
13
+ # "Software"), to deal in the Software without restriction, including
14
+ # without limitation the rights to use, copy, modify, merge, publish,
15
+ # distribute, sublicense, and/or sell copies of the Software, and to
16
+ # permit persons to whom the Software is furnished to do so, subject to
17
+ # the following conditions:
18
+ #
19
+ # The above copyright notice and this permission notice shall be
20
+ # included in all copies or substantial portions of the Software.
21
+ #
22
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+ #
30
+
31
+ require 'rubygems'
32
+ require 'right_agent/pid_file'
33
+ require 'thread'
34
+
35
+ module RightScale
36
+
37
+ class AgentWatcher
38
+ class AlreadyWatched < Exception; end
39
+ class UnknownAgent < Exception; end
40
+
41
+ # Some Time calculation constants
42
+ # ===
43
+ SECOND = 1
44
+ MINUTE = 60 * SECOND
45
+ HOUR = 60 * MINUTE
46
+ DAY = 24 * HOUR
47
+ # ===
48
+
49
+ DEFAULT_FREQUENCY_CHECK = 5 * SECOND
50
+
51
+ def initialize(logger, pid_dir=nil)
52
+ @logger = logger
53
+ @pid_dir = pid_dir
54
+ @running = false
55
+ @stopped_list = {}
56
+ @watched_list = {}
57
+ @watch_list_lock = Monitor.new
58
+ end
59
+
60
+ def log_info(s)
61
+ @logger.call("AgentWatcher: #{s}")
62
+ end
63
+
64
+ def kill_agent(identity, signal='SIGKILL')
65
+ @watch_list_lock.synchronize do
66
+ raise UnknownAgent("#{identity} is not a known agent.") unless @watched_list.has_key?(identity)
67
+ agent = @watched_list.delete(identity)
68
+ Process.kill(signal, agent[:pid].read_pid[:pid])
69
+ @stopped_list[identity] = agent
70
+ end
71
+ end
72
+
73
+ def restart_agent(identity)
74
+ stop_agent(identity)
75
+ start_agent(identity)
76
+ end
77
+
78
+ def start_watching()
79
+ return if @running
80
+ # This logic is implemented with a priority queue of "next check" times:
81
+ #
82
+ # This allows us not to have to start a bunch of timers and do time
83
+ # alrithmatic which can be tricky when someone goes and changes the date
84
+ # on the system this code is running.
85
+
86
+ # Initialize all agents
87
+ @watch_list_lock.synchronize {
88
+ @watched_list.each { |k, v| v[:next_check] = 0 }
89
+ }
90
+
91
+ log_info("Starting the AgentWatcher.")
92
+ @agent_watcher_thread = Thread.new do
93
+ @running = true
94
+ while @running
95
+ next_check = 0
96
+ time_start = Time.now
97
+
98
+ # TODO: This may need to be refactored into a real priority queue if we
99
+ # start to have large amounts of agents assigned, rather than incur the
100
+ # overhead of discovering the next smallest number every iteration. -brs
101
+ @watch_list_lock.synchronize do
102
+ # No use doing anything till we have something to work on, I would have
103
+ # rather used a ConditionVariable here, but they are not compatible with
104
+ # Monitor objects, and I need reentrance.
105
+ sleep DEFAULT_FREQUENCY_CHECK until @watched_list.size > 0 or not @running
106
+
107
+ # Check all processes in the list with a next check time of zero
108
+ # replacing the next check time with their frequency.
109
+ @watched_list.each do |k,v|
110
+ if v[:next_check] <= 0
111
+ v[:next_check] = v[:freq]
112
+ check_agent(k)
113
+ end
114
+ end
115
+
116
+ # Find the lowest next check
117
+ @watched_list.each do |k,v|
118
+ next_check = v[:next_check] unless (next_check > 0 and next_check < v[:next_check])
119
+ end
120
+
121
+ # Subtract this from all the elements before we sleep
122
+ @watched_list.each do |k,v|
123
+ v[:next_check] -= next_check
124
+ end
125
+ end
126
+
127
+ # Account for the time it took to check agents and find the next
128
+ # check time.
129
+ next_check -= (Time.now - time_start).to_i
130
+
131
+ # Sleep for the next check time
132
+ next_check -= sleep(next_check) while (next_check > 0 and @running)
133
+ end
134
+ log_info("Shutting down.")
135
+ end
136
+ end
137
+
138
+ def start_agent(identity)
139
+ @watch_list_lock.synchronize {
140
+ raise UnknownAgent("#{identity} is not a known stopped agent.") unless @stopped_list.has_key?(identity)
141
+ agent = @stopped_list.delete(identity)
142
+ agent[:pid].remove
143
+ system("#{agent[:exec]} #{agent[:start_opts]}")
144
+ log_info("Successfully started the #{identity} agent.")
145
+ # Give us some time to come up before the next check...should be good in
146
+ # 60 seconds I would think.
147
+ agent[:next_check] = MINUTE
148
+ @watched_list[identity] = agent
149
+ }
150
+ end
151
+
152
+ def stop_watching()
153
+ return unless @running
154
+ log_info("Stopping the AgentWatcher.")
155
+ @running = false
156
+ @agent_watcher_thread.terminate
157
+ @agent_watcher_thread.join
158
+ @agent_watcher_thread = nil
159
+ log_info("AgentWatcher Stopped.")
160
+ end
161
+
162
+ def stop_agent(identity)
163
+ @watch_list_lock.synchronize {
164
+ raise UnknownAgent("#{identity} is not a known agent.") unless @watched_list.has_key?(identity)
165
+ agent = @watched_list.delete(identity)
166
+ if system("#{agent[:exec]} #{agent[:stop_opts]}")
167
+ log_info("Successfully stopped the #{identity} agent.")
168
+ agent[:pid].remove
169
+ end
170
+ @stopped_list[identity] = agent
171
+ }
172
+ end
173
+
174
+ def watch_agent(identity, exec, start_opts, stop_opts, freq=DEFAULT_FREQUENCY_CHECK)
175
+ # Make things simple for now and require a resolution of 1 second
176
+ # for the frequency check.
177
+ raise BadFrequency.new unless (freq > 1)
178
+
179
+ # Protect the watch list from the thread monitoring the agents
180
+ @watch_list_lock.synchronize {
181
+ unless @watched_list.has_key?(identity)
182
+
183
+ # If we were given a block, use that for state change, otherwise restart
184
+ action = (block_given? && Proc.new) || Proc.new do |identity, state, mesg|
185
+ if state == :stopped
186
+ log_info("#{identity} has stopped, restarting now.")
187
+ self.start_agent(identity)
188
+ end
189
+ end
190
+
191
+ @watched_list[identity] = {
192
+ :action=>action,
193
+ :exec=>exec,
194
+ :start_opts=>start_opts,
195
+ :stop_opts=>stop_opts,
196
+ :freq=>freq,
197
+ :pid=>PidFile.new(identity,@pid_dir),
198
+ }
199
+ else
200
+ raise AlreadyWatched.new("The agent [#{identity}] is already being watched by us.")
201
+ end
202
+ }
203
+ end
204
+
205
+ private
206
+
207
+ def agent_running?(identity)
208
+ # The check method really tells us if the agent ISN'T running
209
+ # and throws an exception if it is...poorly named I know
210
+ @watch_list_lock.synchronize do
211
+ begin
212
+ @watched_list[identity][:pid].check
213
+ false
214
+ rescue PidFile::AlreadyRunning
215
+ true
216
+ end
217
+ end
218
+ end
219
+
220
+ def check_agent(identity)
221
+ @watch_list_lock.synchronize do
222
+ test_agent = agent_running?(identity)
223
+ unless test_agent
224
+ agent = @watched_list.delete(identity)
225
+ @stopped_list[identity] = agent
226
+ agent[:action].call(identity, :stopped, "The #{identity} agent does not appear to be running!")
227
+ end
228
+ end
229
+ end
230
+
231
+ end
232
+
233
+ end
@@ -0,0 +1,104 @@
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
+
24
+ module RightScale
25
+
26
+ # This class acts as a recipient of audit requests sent by the cook
27
+ # process.
28
+ # The audit proxy which will forward the audits to the core should be
29
+ # initialized before each invocation to cook
30
+ class AuditCookStub
31
+
32
+ include RightSupport::Ruby::EasySingleton
33
+
34
+ def initialize
35
+ @auditors = {}
36
+ @close_callbacks = {}
37
+ end
38
+
39
+ # Sets up the audit proxy that should be used to forward all audit commands.
40
+ #
41
+ # === Parameters
42
+ # thread_name(String):: execution thread name or default
43
+ # auditor(AuditProxy):: audit proxy
44
+ def setup_audit_forwarding(thread_name, auditor)
45
+ @auditors ||= {}
46
+ @auditors[thread_name] = auditor
47
+ end
48
+
49
+ # Forward audit command received from cook using audit proxy
50
+ #
51
+ # === Parameters
52
+ # kind(Symbol):: Kind of audit, one of :append_info, :append_error, :create_new_section, :update_status and :append_output
53
+ # text(String):: Audit content
54
+ # thread_name(String):: thread name for audit or default
55
+ # options[:category]:: Optional, associated event category, one of RightScale::EventCategories
56
+ #
57
+ # === Raise
58
+ # RuntimeError:: If audit_proxy is not set prior to calling this
59
+ def forward_audit(kind, text, thread_name, options)
60
+ auditor = @auditors[thread_name]
61
+ return unless auditor
62
+ if kind == :append_output
63
+ auditor.append_output(text)
64
+ else
65
+ auditor.__send__(kind, text, options)
66
+ end
67
+ end
68
+
69
+ # Register listener for when audit proxy is closed/reset
70
+ # Listener is executable sequence proxy to synchronize betweek
71
+ # cook process going away and all audits having been processed
72
+ #
73
+ # === Parameters
74
+ # thread_name(String):: execution thread name or default
75
+ #
76
+ # === Block
77
+ # Given block should not take any argument and gets called back when proxy is reset
78
+ #
79
+ # === Return
80
+ # true:: Always return true
81
+ def on_close(thread_name, &blk)
82
+ @close_callbacks[thread_name] = blk
83
+ true
84
+ end
85
+
86
+ # Reset proxy object and notify close event listener
87
+ #
88
+ # === Parameters
89
+ # thread_name(String):: execution thread name or default
90
+ #
91
+ # === Return
92
+ # true:: Always return true
93
+ def close(thread_name)
94
+ close_callback = @close_callbacks[thread_name]
95
+ close_callback.call if close_callback
96
+ true
97
+ ensure
98
+ @auditors[thread_name] = nil
99
+ @close_callbacks[thread_name] = nil
100
+ end
101
+
102
+ end
103
+
104
+ end