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,211 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009-2012 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
|
+
# Manages and persists chef state (run list and attributes)
|
28
|
+
class ChefState
|
29
|
+
|
30
|
+
# Path to JSON file where current chef state is serialized
|
31
|
+
STATE_FILE = File.join(InstanceState::STATE_DIR, 'chef.js')
|
32
|
+
|
33
|
+
# Path to JSON file where past scripts are serialized
|
34
|
+
SCRIPTS_FILE = File.join(InstanceState::STATE_DIR, 'past_scripts.js')
|
35
|
+
|
36
|
+
class ChefStateNotInitialized < Exception; end
|
37
|
+
|
38
|
+
class << self
|
39
|
+
# Load chef state from file
|
40
|
+
#
|
41
|
+
# @param [String] agent_id identity
|
42
|
+
# @param [String] secret for encryption or nil
|
43
|
+
# @param [TrueClass|FalseClass] reset persisted state if true, load it otherwise
|
44
|
+
def init(agent_id, secret, reset)
|
45
|
+
return true if initialized? && !reset
|
46
|
+
@@encoder = MessageEncoder.for_agent(agent_id, secret)
|
47
|
+
@@attributes = {}
|
48
|
+
@@past_scripts = []
|
49
|
+
if reset
|
50
|
+
save_state
|
51
|
+
else
|
52
|
+
load_state
|
53
|
+
end
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
# Was 'init' ever called?
|
58
|
+
# Note: Accessing or setting the chef state calls 'init'
|
59
|
+
#
|
60
|
+
# === Return
|
61
|
+
# true:: If 'init' has been called
|
62
|
+
# false:: Otherwise
|
63
|
+
def initialized?
|
64
|
+
!!defined?(@@attributes)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Current node attributes
|
68
|
+
#
|
69
|
+
# === Return
|
70
|
+
# attributes(Hash):: Current node attributes
|
71
|
+
def attributes
|
72
|
+
ensure_initialized
|
73
|
+
@@attributes
|
74
|
+
end
|
75
|
+
|
76
|
+
# Current list of scripts that have already executed
|
77
|
+
#
|
78
|
+
# === Return
|
79
|
+
# (Array[(String)]) Scripts that have already executed
|
80
|
+
def past_scripts
|
81
|
+
ensure_initialized
|
82
|
+
@@past_scripts
|
83
|
+
end
|
84
|
+
|
85
|
+
# Set node attributes
|
86
|
+
# Note: can't set it to nil. Setting the attributes to nil will
|
87
|
+
# cause the attributes to be initialized if they haven't yet but won't
|
88
|
+
# assign the value nil to them.
|
89
|
+
#
|
90
|
+
# === Parameters
|
91
|
+
# attributes(Hash):: Node attributes
|
92
|
+
#
|
93
|
+
# === Return
|
94
|
+
# true:: Always return true
|
95
|
+
def attributes=(val)
|
96
|
+
ensure_initialized
|
97
|
+
@@attributes = val if val
|
98
|
+
save_state
|
99
|
+
end
|
100
|
+
|
101
|
+
# Merge given attributes into node attributes
|
102
|
+
#
|
103
|
+
# === Parameters
|
104
|
+
# attribs(Hash):: Attributes to be merged
|
105
|
+
#
|
106
|
+
# === Return
|
107
|
+
# true:: Always return true
|
108
|
+
def merge_attributes(attribs)
|
109
|
+
self.attributes = ::RightSupport::Data::HashTools.deep_merge!(attributes, attribs) if attribs
|
110
|
+
true
|
111
|
+
end
|
112
|
+
|
113
|
+
# Record script execution in scripts file
|
114
|
+
#
|
115
|
+
# === Parameters
|
116
|
+
# nickname(String):: Nickname of RightScript which successfully executed
|
117
|
+
#
|
118
|
+
# === Return
|
119
|
+
# true:: If script was added to past scripts collection
|
120
|
+
# false:: If script was already in past scripts collection
|
121
|
+
def record_script_execution(nickname)
|
122
|
+
ensure_initialized
|
123
|
+
new_script = !@@past_scripts.include?(nickname)
|
124
|
+
@@past_scripts << nickname if new_script
|
125
|
+
# note that we only persist state on successful execution of bundle.
|
126
|
+
new_script
|
127
|
+
end
|
128
|
+
|
129
|
+
# Save node attributes to file
|
130
|
+
# Note: Attributes are saved only when runlist ran on default thread
|
131
|
+
#
|
132
|
+
# === Return
|
133
|
+
# true:: Always return true
|
134
|
+
def save_state
|
135
|
+
if Cook.instance.has_default_thread?
|
136
|
+
begin
|
137
|
+
FileUtils.touch(STATE_FILE)
|
138
|
+
File.chmod(0600, STATE_FILE)
|
139
|
+
write_encoded_data(STATE_FILE, { 'attributes' => @@attributes })
|
140
|
+
RightScale::JsonUtilities::write_json(SCRIPTS_FILE, @@past_scripts)
|
141
|
+
rescue Exception => e
|
142
|
+
Log.warning("Failed to save node attributes: #{e.message}")
|
143
|
+
end
|
144
|
+
end
|
145
|
+
true
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
def ensure_initialized
|
150
|
+
raise ChefStateNotInitialized if !initialized?
|
151
|
+
end
|
152
|
+
|
153
|
+
# Loads Chef state from file(s), if any.
|
154
|
+
#
|
155
|
+
# === Return
|
156
|
+
# always true
|
157
|
+
def load_state
|
158
|
+
# load the previously saved Chef node attributes, if any.
|
159
|
+
if File.file?(STATE_FILE)
|
160
|
+
begin
|
161
|
+
js = read_encoded_data(STATE_FILE)
|
162
|
+
@@attributes = js['attributes'] || {}
|
163
|
+
Log.debug("Successfully loaded chef state")
|
164
|
+
rescue Exception => e
|
165
|
+
Log.error("Failed to load chef state", e)
|
166
|
+
end
|
167
|
+
else
|
168
|
+
@@attributes = {}
|
169
|
+
Log.debug("No previous state to load")
|
170
|
+
end
|
171
|
+
|
172
|
+
# load the list of previously run scripts
|
173
|
+
@@past_scripts = RightScale::JsonUtilities::read_json(SCRIPTS_FILE) rescue [] if File.file?(SCRIPTS_FILE)
|
174
|
+
Log.debug("Past scripts: #{@@past_scripts.inspect}")
|
175
|
+
true
|
176
|
+
end
|
177
|
+
|
178
|
+
# Encode and save an object to a file
|
179
|
+
#
|
180
|
+
# === Parameters
|
181
|
+
# path(String):: Path to file being written
|
182
|
+
# data(Object):: Object to be saved
|
183
|
+
#
|
184
|
+
# === Return
|
185
|
+
# true:: Always return true
|
186
|
+
def write_encoded_data(path, data)
|
187
|
+
dir = File.dirname(path)
|
188
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
189
|
+
File.open(path, 'w') do |f|
|
190
|
+
f.flock(File::LOCK_EX)
|
191
|
+
f.write(@@encoder.encode(data))
|
192
|
+
end
|
193
|
+
true
|
194
|
+
end
|
195
|
+
|
196
|
+
# Read encoded content form given file and return the origin al object
|
197
|
+
#
|
198
|
+
# === Parameters
|
199
|
+
# path(String):: Path to file being written
|
200
|
+
#
|
201
|
+
# === Return
|
202
|
+
# data(Object):: Object restored from file content
|
203
|
+
def read_encoded_data(path)
|
204
|
+
File.open(path, "r") do |f|
|
205
|
+
f.flock(File::LOCK_EX)
|
206
|
+
return @@encoder.decode(f.read)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,306 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2010-2012 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_agent'
|
24
|
+
require 'right_agent/core_payload_types'
|
25
|
+
|
26
|
+
|
27
|
+
require File.normalize_path(File.join(File.dirname(__FILE__), '..', '..', 'chef', 'right_providers'))
|
28
|
+
require File.normalize_path(File.join(File.dirname(__FILE__), '..', '..', 'chef', 'plugins'))
|
29
|
+
|
30
|
+
module RightScale
|
31
|
+
|
32
|
+
class Cook
|
33
|
+
|
34
|
+
# Name of agent running the cook process
|
35
|
+
AGENT_NAME = 'instance'
|
36
|
+
|
37
|
+
# Exceptions
|
38
|
+
class TagError < Exception; end
|
39
|
+
class BlockingError < Exception; end
|
40
|
+
|
41
|
+
# Run bundle given in stdin
|
42
|
+
def run
|
43
|
+
# 1. Load configuration settings
|
44
|
+
options = OptionsBag.load
|
45
|
+
agent_id = options[:identity]
|
46
|
+
AgentConfig.root_dir = options[:root_dir]
|
47
|
+
|
48
|
+
Log.program_name = 'RightLink'
|
49
|
+
Log.facility = 'user'
|
50
|
+
Log.log_to_file_only(options[:log_to_file_only])
|
51
|
+
Log.init(agent_id, options[:log_path])
|
52
|
+
Log.level = CookState.log_level
|
53
|
+
# add an additional logger if the agent is set to log to an alternate
|
54
|
+
# location (install, operate, decommission, ...)
|
55
|
+
Log.add_logger(::Logger.new(CookState.log_file)) if CookState.log_file
|
56
|
+
|
57
|
+
Log.info("[cook] Process starting up with dev tags: [#{CookState.startup_tags.select { |tag| tag.include?(CookState::DEV_TAG_NAMESPACE)}.join(', ')}]")
|
58
|
+
fail('Missing command server listen port') unless options[:listen_port]
|
59
|
+
fail('Missing command cookie') unless options[:cookie]
|
60
|
+
@client = CommandClient.new(options[:listen_port], options[:cookie])
|
61
|
+
ShutdownRequestProxy.init(@client)
|
62
|
+
|
63
|
+
# 2. Retrieve bundle
|
64
|
+
input = gets.chomp
|
65
|
+
begin
|
66
|
+
bundle = RightScale::MessageEncoder.for_agent(agent_id).decode(input)
|
67
|
+
rescue Exception => e
|
68
|
+
fail('Invalid bundle', e.message)
|
69
|
+
end
|
70
|
+
|
71
|
+
fail('Missing bundle', 'No bundle to run') if bundle.nil?
|
72
|
+
|
73
|
+
@thread_name = bundle.runlist_policy.thread_name if bundle.respond_to?(:runlist_policy) && bundle.runlist_policy
|
74
|
+
@thread_name ||= RightScale::AgentConfig.default_thread_name
|
75
|
+
options[:thread_name] = @thread_name
|
76
|
+
|
77
|
+
# Chef state needs the server secret so it can encrypt state on disk.
|
78
|
+
# The secret is the same for all instances of the server (i.e. is still
|
79
|
+
# valid after stop and restart server).
|
80
|
+
server_secret = bundle.server_secret || AgentConfig.default_server_secret
|
81
|
+
ChefState.init(agent_id, server_secret, reset=false)
|
82
|
+
|
83
|
+
# 3. Run bundle
|
84
|
+
@@instance = self
|
85
|
+
success = nil
|
86
|
+
Log.debug("[cook] Thread name associated with bundle = #{@thread_name}")
|
87
|
+
gatherer = ExternalParameterGatherer.new(bundle, options)
|
88
|
+
sequence = ExecutableSequence.new(bundle)
|
89
|
+
EM.threadpool_size = 1
|
90
|
+
EM.error_handler do |e|
|
91
|
+
Log.error("Execution failed", e, :trace)
|
92
|
+
fail('Exception caught', "The following exception was caught during execution:\n #{e.message}")
|
93
|
+
end
|
94
|
+
EM.run do
|
95
|
+
begin
|
96
|
+
AuditStub.instance.init(options)
|
97
|
+
gatherer.callback { EM.defer { sequence.run } }
|
98
|
+
gatherer.errback { success = false; report_failure(gatherer) }
|
99
|
+
sequence.callback { success = true; send_inputs_patch(sequence) }
|
100
|
+
sequence.errback { success = false; report_failure(sequence) }
|
101
|
+
|
102
|
+
EM.defer { gatherer.run }
|
103
|
+
rescue Exception => e
|
104
|
+
fail('Execution failed', Log.format("Execution failed", e, :trace))
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
rescue Exception => e
|
109
|
+
fail('Execution failed', Log.format("Run failed", e, :trace))
|
110
|
+
|
111
|
+
ensure
|
112
|
+
Log.info("[cook] Process stopping")
|
113
|
+
exit(1) unless success
|
114
|
+
end
|
115
|
+
|
116
|
+
# Determines if the current cook process has the default thread for purposes
|
117
|
+
# of concurrency with non-defaulted cooks.
|
118
|
+
def has_default_thread?
|
119
|
+
::RightScale::AgentConfig.default_thread_name == @thread_name
|
120
|
+
end
|
121
|
+
|
122
|
+
# Helper method to send a request to one or more targets with no response expected
|
123
|
+
# See InstanceCommands for details
|
124
|
+
def send_push(type, payload = nil, target = nil, opts = {})
|
125
|
+
cmd = {:name => :send_push, :type => type, :payload => payload, :target => target, :options => opts}
|
126
|
+
# Need to execute on EM main thread where command client is running
|
127
|
+
EM.next_tick { @client.send_command(cmd) }
|
128
|
+
end
|
129
|
+
|
130
|
+
# Add given tag to tags exposed by corresponding server
|
131
|
+
#
|
132
|
+
# === Parameters
|
133
|
+
# tag(String):: Tag to be added
|
134
|
+
#
|
135
|
+
# === Return
|
136
|
+
# result(Hash):: contents of response
|
137
|
+
def query_tags(tags, agent_ids=nil, timeout=120)
|
138
|
+
cmd = { :name => :query_tags, :tags => tags }
|
139
|
+
cmd[:agent_ids] = agent_ids unless agent_ids.nil? || agent_ids.empty?
|
140
|
+
response = blocking_request(cmd, timeout)
|
141
|
+
begin
|
142
|
+
result = OperationResult.from_results(load(response, "Unexpected response #{response.inspect}"))
|
143
|
+
raise TagError.new("Query tags failed: #{result.content}") unless result.success?
|
144
|
+
return result.content
|
145
|
+
rescue
|
146
|
+
raise TagError.new("Query tags failed: #{response.inspect}")
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Add given tag to tags exposed by corresponding server
|
151
|
+
#
|
152
|
+
# === Parameters
|
153
|
+
# tag(String):: Tag to be added
|
154
|
+
# timeout(Fixnum):: Number of seconds to wait for agent response
|
155
|
+
#
|
156
|
+
# === Return
|
157
|
+
# true:: Always return true
|
158
|
+
def add_tag(tag_name, timeout)
|
159
|
+
cmd = { :name => :add_tag, :tag => tag_name }
|
160
|
+
response = blocking_request(cmd, timeout)
|
161
|
+
result = OperationResult.from_results(load(response, "Unexpected response #{response.inspect}"))
|
162
|
+
if result.success?
|
163
|
+
::Chef::Log.info("Successfully added tag #{tag_name}")
|
164
|
+
else
|
165
|
+
raise TagError.new("Add tag failed: #{result.content}")
|
166
|
+
end
|
167
|
+
true
|
168
|
+
end
|
169
|
+
|
170
|
+
# Remove given tag from tags exposed by corresponding server
|
171
|
+
#
|
172
|
+
# === Parameters
|
173
|
+
# tag(String):: Tag to be removed
|
174
|
+
# timeout(Fixnum):: Number of seconds to wait for agent response
|
175
|
+
#
|
176
|
+
# === Return
|
177
|
+
# true:: Always return true
|
178
|
+
def remove_tag(tag_name, timeout)
|
179
|
+
cmd = { :name => :remove_tag, :tag => tag_name }
|
180
|
+
response = blocking_request(cmd, timeout)
|
181
|
+
result = OperationResult.from_results(load(response, "Unexpected response #{response.inspect}"))
|
182
|
+
if result.success?
|
183
|
+
::Chef::Log.info("Successfully removed tag #{tag_name}")
|
184
|
+
else
|
185
|
+
raise TagError.new("Remove tag failed: #{result.content}")
|
186
|
+
end
|
187
|
+
true
|
188
|
+
end
|
189
|
+
|
190
|
+
# Retrieve current instance tags
|
191
|
+
#
|
192
|
+
# === Parameters
|
193
|
+
# timeout(Fixnum):: Number of seconds to wait for agent response
|
194
|
+
def load_tags(timeout)
|
195
|
+
cmd = { :name => :get_tags }
|
196
|
+
res = blocking_request(cmd, timeout)
|
197
|
+
raise TagError.new("Retrieving current tags failed: #{res.inspect}") unless res.kind_of?(Array)
|
198
|
+
|
199
|
+
::Chef::Log.info("Successfully loaded current tags: '#{res.join("', '")}'")
|
200
|
+
res
|
201
|
+
end
|
202
|
+
|
203
|
+
# Access cook instance from anywhere to send requests to core through
|
204
|
+
# command protocol
|
205
|
+
def self.instance
|
206
|
+
@@instance
|
207
|
+
end
|
208
|
+
|
209
|
+
protected
|
210
|
+
|
211
|
+
# Initialize instance variables
|
212
|
+
def initialize
|
213
|
+
@client = nil
|
214
|
+
end
|
215
|
+
|
216
|
+
# Report inputs patch to core
|
217
|
+
def send_inputs_patch(sequence)
|
218
|
+
if has_default_thread?
|
219
|
+
begin
|
220
|
+
cmd = { :name => :set_inputs_patch, :patch => sequence.inputs_patch }
|
221
|
+
@client.send_command(cmd)
|
222
|
+
rescue Exception => e
|
223
|
+
fail('Failed to update inputs', Log.format("Failed to apply inputs patch after execution", e, :trace))
|
224
|
+
end
|
225
|
+
end
|
226
|
+
true
|
227
|
+
ensure
|
228
|
+
stop
|
229
|
+
end
|
230
|
+
|
231
|
+
# Report failure to core
|
232
|
+
def report_failure(subject)
|
233
|
+
begin
|
234
|
+
AuditStub.instance.append_error(subject.failure_title, :category => RightScale::EventCategories::CATEGORY_ERROR) if subject.failure_title
|
235
|
+
AuditStub.instance.append_error(subject.failure_message) if subject.failure_message
|
236
|
+
rescue Exception => e
|
237
|
+
fail('Failed to report failure', Log.format("Failed to report failure after execution", e, :trace))
|
238
|
+
ensure
|
239
|
+
stop
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# Print failure message and exit abnormally
|
244
|
+
def fail(title, message=nil)
|
245
|
+
$stderr.puts title
|
246
|
+
$stderr.puts message || title
|
247
|
+
if @client
|
248
|
+
@client.stop { AuditStub.instance.stop { exit(1) } }
|
249
|
+
else
|
250
|
+
exit(1)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# Stop command client then stop auditor stub then EM
|
255
|
+
def stop
|
256
|
+
AuditStub.instance.stop do
|
257
|
+
@client.stop do |timeout|
|
258
|
+
Log.info('[cook] Failed to stop command client cleanly, forcing shutdown...') if timeout
|
259
|
+
EM.stop
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# Provides a blocking request for the given command
|
265
|
+
# Can only be called when on EM defer thread
|
266
|
+
#
|
267
|
+
# === Parameters
|
268
|
+
# cmd(Hash):: request to send
|
269
|
+
#
|
270
|
+
# === Return
|
271
|
+
# response(String):: raw response
|
272
|
+
#
|
273
|
+
# === Raise
|
274
|
+
# BlockingError:: If request called when on EM main thread
|
275
|
+
def blocking_request(cmd, timeout)
|
276
|
+
raise BlockingError, "Blocking request not allowed on EM main thread for command #{cmd.inspect}" if EM.reactor_thread?
|
277
|
+
# Use a queue to block and wait for response
|
278
|
+
response_queue = Queue.new
|
279
|
+
# Need to execute on EM main thread where command client is running
|
280
|
+
EM.next_tick { @client.send_command(cmd, false, timeout) { |response| response_queue << response } }
|
281
|
+
return response_queue.shift
|
282
|
+
end
|
283
|
+
|
284
|
+
# Load serialized content
|
285
|
+
# fail if serialized data is invalid
|
286
|
+
#
|
287
|
+
# === Parameters
|
288
|
+
# data(String):: Serialized content
|
289
|
+
# error_message(String):: Error to be logged/audited in case of failure
|
290
|
+
# format(Symbol):: Serialization format
|
291
|
+
#
|
292
|
+
# === Return
|
293
|
+
# content(String):: Unserialized content
|
294
|
+
def load(data, error_message, format = nil)
|
295
|
+
serializer = Serializer.new(format)
|
296
|
+
content = nil
|
297
|
+
begin
|
298
|
+
content = serializer.load(data)
|
299
|
+
rescue Exception => e
|
300
|
+
fail(error_message, "Failed to load #{serializer.format.to_s} data (#{e}):\n#{data.inspect}")
|
301
|
+
end
|
302
|
+
content
|
303
|
+
end
|
304
|
+
|
305
|
+
end
|
306
|
+
end
|