right_link 5.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/actors/agent_manager.rb +88 -0
- data/actors/instance_scheduler.rb +321 -0
- data/actors/instance_services.rb +64 -0
- data/actors/instance_setup.rb +567 -0
- data/bin/cloud +25 -0
- data/bin/cook_runner +44 -0
- data/bin/deploy +120 -0
- data/bin/enroll +385 -0
- data/bin/rad +32 -0
- data/bin/rchk +29 -0
- data/bin/rnac +39 -0
- data/bin/rs_connect +33 -0
- data/bin/rs_log_level +31 -0
- data/bin/rs_ohai +28 -0
- data/bin/rs_reenroll +31 -0
- data/bin/rs_run_recipe +34 -0
- data/bin/rs_run_right_script +34 -0
- data/bin/rs_shutdown +33 -0
- data/bin/rs_tag +33 -0
- data/bin/rs_thunk +33 -0
- data/bin/rstat +31 -0
- data/bin/system +16 -0
- data/ext/Rakefile +18 -0
- data/init/config.yml +5 -0
- data/init/init.rb +79 -0
- data/lib/chef/ohai_setup.rb +51 -0
- data/lib/chef/plugins/cloud.rb +91 -0
- data/lib/chef/plugins/cloudstack.rb +23 -0
- data/lib/chef/plugins/ec2.rb +23 -0
- data/lib/chef/plugins/linux/block_device2.rb +24 -0
- data/lib/chef/plugins/rackspace.rb +23 -0
- data/lib/chef/plugins/rightscale.rb +125 -0
- data/lib/chef/plugins/windows/network.rb +114 -0
- data/lib/chef/plugins.rb +74 -0
- data/lib/chef/providers/dns_dnsmadeeasy_provider.rb +81 -0
- data/lib/chef/providers/dns_resource.rb +100 -0
- data/lib/chef/providers/executable_schedule_provider.rb +70 -0
- data/lib/chef/providers/executable_schedule_resource.rb +144 -0
- data/lib/chef/providers/remote_recipe_provider.rb +86 -0
- data/lib/chef/providers/remote_recipe_resource.rb +101 -0
- data/lib/chef/providers/right_link_tag_provider.rb +73 -0
- data/lib/chef/providers/right_link_tag_resource.rb +59 -0
- data/lib/chef/providers/right_script_provider.rb +190 -0
- data/lib/chef/providers/right_script_resource.rb +113 -0
- data/lib/chef/providers/rs_shutdown_provider.rb +75 -0
- data/lib/chef/providers/rs_shutdown_resource.rb +55 -0
- data/lib/chef/providers/server_collection_provider.rb +66 -0
- data/lib/chef/providers/server_collection_resource.rb +93 -0
- data/lib/chef/providers/windows/powershell_provider.rb +151 -0
- data/lib/chef/providers/windows/powershell_resource.rb +111 -0
- data/lib/chef/providers/windows/unsupported_provider.rb +51 -0
- data/lib/chef/right_providers.rb +55 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ChefNodeCmdlet.csproj +104 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ChefNodeCmdlet.dll-Help.xml +141 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/Exceptions.cs +182 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetChefNodeCommand.cs +58 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetChefNodeRequest.cs +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetChefNodeResponse.cs +45 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetCurrentResourceCommand.cs +58 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetCurrentResourceRequest.cs +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetCurrentResourceResponse.cs +45 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNewResourceCommand.cs +58 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNewResourceRequest.cs +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNewResourceResponse.cs +45 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNextActionCommand.cs +178 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNextActionRequest.cs +67 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNextActionResponse.cs +58 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNodeValueCommandBase.cs +142 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNodeValueRequestBase.cs +64 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNodeValueResponseBase.cs +69 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/JsonTransport.cs +110 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/PipeClient.cs +158 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/PipeServer.cs +142 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/Properties/AssemblyInfo.cs +16 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ProtocolConstants.cs +55 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ProtocolUtilities.cs +77 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ReadMe.txt +53 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetChefNodeCommand.cs +59 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetChefNodeRequest.cs +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetChefNodeResponse.cs +58 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetCurrentResourceCommand.cs +59 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetCurrentResourceRequest.cs +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetCurrentResourceResponse.cs +40 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNewResourceCommand.cs +59 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNewResourceRequest.cs +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNewResourceResponse.cs +40 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNodeValueCommandBase.cs +293 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNodeValueRequestBase.cs +75 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNodeValueResponseBase.cs +45 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/Transport.cs +91 -0
- data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet.sln +35 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestChefNodeCmdlet/Program.cs +374 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestChefNodeCmdlet/Properties/AssemblyInfo.cs +16 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestChefNodeCmdlet/TestChefNodeCmdlet.csproj +65 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/Program.cs +136 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/Properties/AssemblyInfo.cs +36 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/ReadMe.txt +46 -0
- data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/TestNextActionCmdlet.csproj +68 -0
- data/lib/chef/windows/bin/Newtonsoft.Json.dll +0 -0
- data/lib/chef/windows/chef_node_server.rb +463 -0
- data/lib/chef/windows/dynamic_powershell_provider.rb +296 -0
- data/lib/chef/windows/pipe_server.rb +283 -0
- data/lib/chef/windows/powershell_host.rb +285 -0
- data/lib/chef/windows/powershell_pipe_server.rb +136 -0
- data/lib/chef/windows/powershell_provider_base.rb +92 -0
- data/lib/chef/windows/scripts/run_loop.ps1 +105 -0
- data/lib/clouds/cloud.rb +557 -0
- data/lib/clouds/cloud_factory.rb +250 -0
- data/lib/clouds/cloud_utilities.rb +244 -0
- data/lib/clouds/clouds/azure.rb +106 -0
- data/lib/clouds/clouds/cloudstack.rb +114 -0
- data/lib/clouds/clouds/ec2.rb +113 -0
- data/lib/clouds/clouds/eucalyptus.rb +46 -0
- data/lib/clouds/clouds/google.rb +102 -0
- data/lib/clouds/clouds/none.rb +76 -0
- data/lib/clouds/clouds/openstack.rb +30 -0
- data/lib/clouds/clouds/rackspace-ng.rb +54 -0
- data/lib/clouds/clouds/rackspace.rb +78 -0
- data/lib/clouds/clouds/softlayer.rb +91 -0
- data/lib/clouds/metadata_formatter.rb +108 -0
- data/lib/clouds/metadata_provider.rb +128 -0
- data/lib/clouds/metadata_source.rb +87 -0
- data/lib/clouds/metadata_sources/certificate_metadata_source.rb +207 -0
- data/lib/clouds/metadata_sources/config_drive_metadata_source.rb +129 -0
- data/lib/clouds/metadata_sources/file_metadata_source.rb +74 -0
- data/lib/clouds/metadata_sources/http_metadata_source.rb +277 -0
- data/lib/clouds/metadata_sources/selective_metadata_source.rb +122 -0
- data/lib/clouds/metadata_tree_climber.rb +144 -0
- data/lib/clouds/metadata_writer.rb +155 -0
- data/lib/clouds/metadata_writers/dictionary_metadata_writer.rb +72 -0
- data/lib/clouds/metadata_writers/ruby_metadata_writer.rb +76 -0
- data/lib/clouds/metadata_writers/shell_metadata_writer.rb +121 -0
- data/lib/clouds/register_clouds.rb +34 -0
- data/lib/clouds.rb +32 -0
- data/lib/gem_dependencies.rb +83 -0
- data/lib/git_hooks/commit-msg.rb +7 -0
- data/lib/instance/agent_config.rb +168 -0
- data/lib/instance/agent_watcher.rb +233 -0
- data/lib/instance/audit_cook_stub.rb +104 -0
- data/lib/instance/audit_proxy.rb +247 -0
- data/lib/instance/bundle_queue.rb +104 -0
- data/lib/instance/cook/agent_connection.rb +109 -0
- data/lib/instance/cook/audit_logger.rb +165 -0
- data/lib/instance/cook/audit_stub.rb +142 -0
- data/lib/instance/cook/ca-bundle.crt +2794 -0
- data/lib/instance/cook/chef_state.rb +211 -0
- data/lib/instance/cook/cook.rb +306 -0
- data/lib/instance/cook/cook_state.rb +298 -0
- data/lib/instance/cook/cookbook_path_mapping.rb +66 -0
- data/lib/instance/cook/cookbook_repo_retriever.rb +190 -0
- data/lib/instance/cook/executable_sequence.rb +765 -0
- data/lib/instance/cook/external_parameter_gatherer.rb +190 -0
- data/lib/instance/cook/repose_downloader.rb +349 -0
- data/lib/instance/cook/shutdown_request_proxy.rb +121 -0
- data/lib/instance/cook.rb +41 -0
- data/lib/instance/downloader.rb +208 -0
- data/lib/instance/duplicable.rb +67 -0
- data/lib/instance/exceptions.rb +49 -0
- data/lib/instance/executable_sequence_proxy.rb +278 -0
- data/lib/instance/instance_commands.rb +577 -0
- data/lib/instance/instance_state.rb +633 -0
- data/lib/instance/json_utilities.rb +102 -0
- data/lib/instance/login_manager.rb +533 -0
- data/lib/instance/login_user_manager.rb +522 -0
- data/lib/instance/message_encoder.rb +118 -0
- data/lib/instance/multi_thread_bundle_queue.rb +232 -0
- data/lib/instance/operation_context.rb +60 -0
- data/lib/instance/options_bag.rb +65 -0
- data/lib/instance/payload_formatter.rb +46 -0
- data/lib/instance/policy.rb +53 -0
- data/lib/instance/policy_audit.rb +100 -0
- data/lib/instance/policy_manager.rb +146 -0
- data/lib/instance/reenroll_manager.rb +104 -0
- data/lib/instance/right_scripts_cookbook.rb +181 -0
- data/lib/instance/shutdown_request.rb +221 -0
- data/lib/instance/single_thread_bundle_queue.rb +189 -0
- data/lib/instance/volume_management.rb +450 -0
- data/lib/instance.rb +50 -0
- data/lib/repo_conf_generators/apt_conf_generators.rb +106 -0
- data/lib/repo_conf_generators/gem_conf_generators.rb +80 -0
- data/lib/repo_conf_generators/rightscale_conf_generators.rb +254 -0
- data/lib/repo_conf_generators/rightscale_key.pub +17 -0
- data/lib/repo_conf_generators/yum_conf_generators.rb +225 -0
- data/lib/repo_conf_generators.rb +30 -0
- data/lib/run_shell.rb +28 -0
- data/scripts/agent_checker.rb +571 -0
- data/scripts/agent_controller.rb +247 -0
- data/scripts/agent_deployer.rb +148 -0
- data/scripts/bundle_runner.rb +336 -0
- data/scripts/cloud_controller.rb +176 -0
- data/scripts/log_level_manager.rb +142 -0
- data/scripts/ohai_runner.rb +33 -0
- data/scripts/reenroller.rb +193 -0
- data/scripts/server_importer.rb +293 -0
- data/scripts/shutdown_client.rb +183 -0
- data/scripts/system_configurator.rb +367 -0
- data/scripts/tagger.rb +381 -0
- data/scripts/thunker.rb +356 -0
- metadata +418 -0
@@ -0,0 +1,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
|