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,296 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2010-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
|
+
module RightScale
|
24
|
+
|
25
|
+
# Dynamically create Chef providers from Powershell scripts.
|
26
|
+
# All the Powershell scripts defining a Chef provider should be contained in
|
27
|
+
# a folder under the cookbook 'powershell_providers' directory. For
|
28
|
+
# example creating an IIS Chef provider exposing a start web site and a stop
|
29
|
+
# web site action in Powershell would involve creating the following file
|
30
|
+
# hierarchy:
|
31
|
+
#
|
32
|
+
# `--iis_cookbook
|
33
|
+
# |-- metadata.json
|
34
|
+
# |-- metadata.rb
|
35
|
+
# |-- powershell_providers
|
36
|
+
# | `-- iis
|
37
|
+
# | |-- _init.ps1
|
38
|
+
# | |-- _load_current_resource.ps1
|
39
|
+
# | |-- start.ps1
|
40
|
+
# | |-- stop.ps1
|
41
|
+
# | `-- _term.ps1
|
42
|
+
# |-- recipes
|
43
|
+
# | |-- default.rb
|
44
|
+
# | |-- install.rb
|
45
|
+
# | |-- restart.rb
|
46
|
+
# | |-- start.rb
|
47
|
+
# | `-- stop.rb
|
48
|
+
# `-- resources
|
49
|
+
# `-- powershell_iis.rb
|
50
|
+
#
|
51
|
+
# In this example, the 'start.rb', 'stop.rb' and 'restart.rb' recipes would
|
52
|
+
# use the 'start' and/or 'stop' actions implemented by the corresponding
|
53
|
+
# Powershell scripts.
|
54
|
+
#
|
55
|
+
# The '_init.ps1' and '_term.ps1' are optional scripts that can contain
|
56
|
+
# initialization and cleanup code respectively. These two scripts are called
|
57
|
+
# once during a single Chef converge and can be used e.g. to load required
|
58
|
+
# .NET assemblies in the Powershell environment used to run the action
|
59
|
+
# scripts.
|
60
|
+
# The '_load_current_resource.ps1' script is also optional. Chef calls this
|
61
|
+
# script right before executing an action if it exists. The script should
|
62
|
+
# load any state from the system that the provider needs in order to run its
|
63
|
+
# actions (in this example this script could check whether the website is
|
64
|
+
# currently running so that the start and stop scripts would know whether any
|
65
|
+
# action is required on their part).
|
66
|
+
#
|
67
|
+
# Note that there should be a light weight resource defined for each
|
68
|
+
# Powershell provider. By default the resource name should match the name of
|
69
|
+
# the provider (that is the name of the folder containing the Powershell
|
70
|
+
# scripts). A lightweight resource can specify a different name for its
|
71
|
+
# corresponding provider though.
|
72
|
+
#
|
73
|
+
# Typical usage for this class involved calling 'generate_providers' multiple
|
74
|
+
# times then inspecting 'validation_errors'
|
75
|
+
class DynamicPowershellProvider
|
76
|
+
|
77
|
+
# Name of directory under cookbook that contains Powershell providers
|
78
|
+
POWERSHELL_PROVIDERS_DIR_NAME = 'powershell_providers'
|
79
|
+
|
80
|
+
# List of files with built-in behavior
|
81
|
+
INIT_SCRIPT = '_init'
|
82
|
+
TERM_SCRIPT = '_term'
|
83
|
+
LOAD_SCRIPT = '_load_current_resource'
|
84
|
+
BUILT_IN_SCRIPTS = [INIT_SCRIPT, TERM_SCRIPT, LOAD_SCRIPT]
|
85
|
+
|
86
|
+
# Hash of Powershell Chef providers validation errors keyed by provider path and
|
87
|
+
# initialized by 'generate_providers'
|
88
|
+
attr_reader :validation_errors
|
89
|
+
|
90
|
+
# Generated providers classes
|
91
|
+
# initialized by 'generate_providers'
|
92
|
+
attr_reader :providers
|
93
|
+
|
94
|
+
# chef class resource class naming
|
95
|
+
include Chef::Mixin::ConvertToClassName
|
96
|
+
|
97
|
+
# Initialize instance
|
98
|
+
def initialize
|
99
|
+
@validation_errors = {}
|
100
|
+
@providers = []
|
101
|
+
@providers_names = []
|
102
|
+
end
|
103
|
+
|
104
|
+
# Generate Chef providers from cookbooks in given path
|
105
|
+
# Initializes 'validation_errors' accordingly
|
106
|
+
# Skip providers that have already been created by this instance
|
107
|
+
#
|
108
|
+
# === Parameters
|
109
|
+
# cookbooks_path(String|Array):: Path(s) to cookbooks directories
|
110
|
+
#
|
111
|
+
# === Return
|
112
|
+
# providers(Array):: List of generated providers names
|
113
|
+
def generate_providers(cookbooks_paths)
|
114
|
+
providers = []
|
115
|
+
cookbooks_paths = [cookbooks_paths] unless cookbooks_paths.is_a?(Array)
|
116
|
+
cookbooks_paths.each do |cookbooks_path|
|
117
|
+
return [] unless File.directory?(cookbooks_path)
|
118
|
+
Dir[File.normalize_path(File.join(cookbooks_path, '*/'))].each do |cookbook_path|
|
119
|
+
cookbook_name = File.basename(cookbook_path)
|
120
|
+
Dir[File.normalize_path(File.join(cookbook_path, POWERSHELL_PROVIDERS_DIR_NAME, '*/'))].each do |provider_file_path|
|
121
|
+
provider_name = filename_to_qualified_string(cookbook_name, provider_file_path)
|
122
|
+
provider_class_name = convert_to_class_name(provider_name)
|
123
|
+
next if @providers_names.include?(provider_class_name)
|
124
|
+
generate_single_provider(provider_class_name, provider_file_path)
|
125
|
+
providers << provider_name
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
@providers_names += providers
|
130
|
+
true
|
131
|
+
end
|
132
|
+
|
133
|
+
protected
|
134
|
+
# Dynamically create provider class
|
135
|
+
#
|
136
|
+
# === Parameters
|
137
|
+
# name(String):: Powershell Chef provider class name
|
138
|
+
# path(String):: Path to directory containing Powershell scripts
|
139
|
+
#
|
140
|
+
# === Return
|
141
|
+
# true:: Always return true
|
142
|
+
def generate_single_provider(name, path)
|
143
|
+
Log.info("[chef] Creating Powershell provider #{name}")
|
144
|
+
all_scripts = Dir[File.join(path, "*#{::RightScale::Platform::Shell::POWERSHELL_V1x0_SCRIPT_EXTENSION}")]
|
145
|
+
action_scripts = all_scripts.select { |s| is_action_script?(s) }
|
146
|
+
|
147
|
+
new_provider = create_provider_class(name) do |provider|
|
148
|
+
action_script_names = []
|
149
|
+
action_scripts.each do |script|
|
150
|
+
action_script_name = File.basename(script, '.*').snake_case
|
151
|
+
action_script_names << action_script_name
|
152
|
+
action_name = "action_#{action_script_name}"
|
153
|
+
Log.info("[chef] Defining #{name}##{action_name} to run '#{script}'")
|
154
|
+
provider.class_eval("def #{action_name}; #{name}.run_script('#{script}'); end")
|
155
|
+
end
|
156
|
+
|
157
|
+
validate_resource_actions(File.join(path, "..", "..", "resources", "#{File.basename(path)}.rb"), action_script_names)
|
158
|
+
|
159
|
+
if load_script = all_scripts.detect { |s| File.basename(s, '.*').downcase == LOAD_SCRIPT }
|
160
|
+
Log.info("[chef] Defining #{name}#load_current_resource to run '#{load_script}'")
|
161
|
+
provider.class_eval(<<-EOF
|
162
|
+
def load_current_resource;
|
163
|
+
@current_resoure = #{resource_class_name(name)}.new(@new_resource.name)
|
164
|
+
RightScale::Windows::ChefNodeServer.instance.current_resource = @current_resource
|
165
|
+
#{name}.run_script('#{load_script}')
|
166
|
+
end
|
167
|
+
EOF
|
168
|
+
)
|
169
|
+
end
|
170
|
+
if init_script = all_scripts.detect { |s| File.basename(s, '.*').downcase == INIT_SCRIPT }
|
171
|
+
Log.info("[chef] Defining #{name}.init to run '#{init_script}'")
|
172
|
+
provider.instance_eval("def init(node); run_script('#{init_script}') if super(node); end")
|
173
|
+
end
|
174
|
+
if term_script = all_scripts.detect { |s| File.basename(s, '.*').downcase == TERM_SCRIPT }
|
175
|
+
Log.info("[chef] Defining #{name}.terminate to run '#{term_script}'")
|
176
|
+
provider.instance_eval("def terminate; begin; run_script('#{term_script}'); ensure; super; end; end")
|
177
|
+
end
|
178
|
+
Log.info("[chef] Done creating #{name}")
|
179
|
+
end
|
180
|
+
|
181
|
+
# register the provider with the default windows platform
|
182
|
+
Chef::Platform.platforms[:windows][:default].merge!(name.snake_case.gsub("::","_").to_sym => new_provider)
|
183
|
+
|
184
|
+
@providers << new_provider
|
185
|
+
true
|
186
|
+
end
|
187
|
+
|
188
|
+
# Given a fully qualified provider class name, generate the fully qualified class name of the associated
|
189
|
+
# resource (for lightweight resources).
|
190
|
+
#
|
191
|
+
# Note: Uses Chef::Mixin::ConvertToClassName to create the resource name in the same manner Chef does when
|
192
|
+
# creating lightweight resources
|
193
|
+
#
|
194
|
+
# === Parameters
|
195
|
+
# provider_class_name(String):: unscoped provider class name. Assumes the following <cookbook name><provider name>
|
196
|
+
#
|
197
|
+
# === Return
|
198
|
+
# (String):: Fully qualified resource class name
|
199
|
+
def resource_class_name(provider_class_name)
|
200
|
+
# Chef lwr/p resource and provider base names are the same
|
201
|
+
"Chef::Resource::#{provider_class_name}"
|
202
|
+
end
|
203
|
+
|
204
|
+
# Creates/overrides class with given name
|
205
|
+
# Also create modules if class name includes '::' and corresponding
|
206
|
+
# modules don't exist yet.
|
207
|
+
#
|
208
|
+
# === Parameters
|
209
|
+
# name(String):: Class name, may include module names as well (e.g. 'Foo::Bar')
|
210
|
+
# mod(Constant):: Module in which class should be created, Object by default
|
211
|
+
#
|
212
|
+
# === Block
|
213
|
+
# Given block should take one argument which corresponds to the class instance
|
214
|
+
def create_provider_class(name, mod=Object, &init)
|
215
|
+
parts = name.split('::', 2)
|
216
|
+
cls = nil
|
217
|
+
if parts.size == 1
|
218
|
+
if mod.const_defined?(name)
|
219
|
+
# Was already previously defined, undef all the known *instance* methods
|
220
|
+
# (class methods are inherited and should not be undefined)
|
221
|
+
cls = mod.const_get(name)
|
222
|
+
(cls.instance_methods - RightScale::PowershellProviderBase.instance_methods).each { |m| cls.class_eval("undef #{m}") }
|
223
|
+
init.call(cls)
|
224
|
+
else
|
225
|
+
# New class
|
226
|
+
cls = Class.new(RightScale::PowershellProviderBase) { |c| init.call(c) }
|
227
|
+
mod.const_set(name, cls)
|
228
|
+
end
|
229
|
+
else
|
230
|
+
m = parts[0]
|
231
|
+
mod = if mod.const_defined?(m)
|
232
|
+
# Recurse into existing module
|
233
|
+
mod.const_get(m)
|
234
|
+
else
|
235
|
+
# Create new module and recurse
|
236
|
+
mod.const_set(m, Module.new)
|
237
|
+
end
|
238
|
+
cls = create_provider_class(parts[1], mod, &init)
|
239
|
+
end
|
240
|
+
cls
|
241
|
+
end
|
242
|
+
|
243
|
+
# Is given filename a valid Chef Powershell provider action script?
|
244
|
+
#
|
245
|
+
# === Parameters
|
246
|
+
# filename(String):: File name to be tested
|
247
|
+
#
|
248
|
+
# === Return
|
249
|
+
# true:: If given filename is a valid Powershell provider action script
|
250
|
+
# false:: Otherwise
|
251
|
+
def is_action_script?(filename)
|
252
|
+
basename = File.basename(filename, '.*').downcase
|
253
|
+
valid_identifier = !!(basename =~ /^[_|a-z]+[a-z|0-9|_]*$/)
|
254
|
+
valid_identifier && !BUILT_IN_SCRIPTS.include?(basename)
|
255
|
+
end
|
256
|
+
|
257
|
+
# extract the list of actions from the given chef lightweight resource file
|
258
|
+
#
|
259
|
+
# === Parameters
|
260
|
+
# path(String):: Path to the resource file to be parsed
|
261
|
+
#
|
262
|
+
# === Return
|
263
|
+
# actions(String|Array):: actions defined for the given resource
|
264
|
+
def load_resource_actions(path)
|
265
|
+
# HACK: the resource file is the only known location of the actions defined for a
|
266
|
+
# given light weight resource. Do a quick and dirty parse of the resource file
|
267
|
+
#looking for the list of actions.
|
268
|
+
resource_content = File.read(path)
|
269
|
+
actions = /^\s*actions\s*(.*)$/.match(resource_content.gsub(/\s*,\s*\n/, ", "))[1].split(',').map { |action| action.strip.gsub(":", "") }
|
270
|
+
actions
|
271
|
+
end
|
272
|
+
|
273
|
+
# warn if resource action is defined, but corresponding powershell script does not exist
|
274
|
+
#
|
275
|
+
# === Parameters
|
276
|
+
# resource_file_path(String):: Path to the resource file to be parsed
|
277
|
+
# action_script_names(String|Array):: names of discovered powershell action scripts for this provider
|
278
|
+
#
|
279
|
+
# === Return
|
280
|
+
# true:: always
|
281
|
+
def validate_resource_actions(resource_file_path, action_script_names)
|
282
|
+
defined_actions = load_resource_actions(resource_file_path) if File.exists?(resource_file_path)
|
283
|
+
unless defined_actions.nil? || defined_actions.empty?
|
284
|
+
missing_action_definitions = []
|
285
|
+
defined_actions.each { |action_name| missing_action_definitions << action_name unless action_script_names.include?(action_name) }
|
286
|
+
if missing_action_definitions.size == 1
|
287
|
+
Log.info("[chef] Warning! no powershell script exists for the action: #{missing_action_definitions.first}")
|
288
|
+
elsif missing_action_definitions.size > 1
|
289
|
+
Log.info("[chef] Warning! no powershell scripts exist for the following actions: #{missing_action_definitions.join(", ")}")
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
true
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
@@ -0,0 +1,283 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2010-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
|
+
require 'rubygems'
|
23
|
+
require 'eventmachine'
|
24
|
+
require 'win32/pipe'
|
25
|
+
require 'tempfile'
|
26
|
+
|
27
|
+
module RightScale
|
28
|
+
|
29
|
+
module Windows
|
30
|
+
|
31
|
+
# Provides an eventmachine callback handler for the server pipe.
|
32
|
+
module PipeServerHandler
|
33
|
+
|
34
|
+
CONNECTING_STATE = 0 # state between client connections
|
35
|
+
READING_STATE = 1 # after connection, receiving request
|
36
|
+
RESPONDING_STATE = 2 # received request, calculating response
|
37
|
+
WRITING_STATE = 3 # calculated response, respond before disconnecting
|
38
|
+
|
39
|
+
WAIT_SLEEP_DELAY_MSECS = 0.001 # yield to avoid busy looping
|
40
|
+
ASYNC_IO_SLEEP_DELAY_MSECS = 0.01 # yield to allow async I/O time to process
|
41
|
+
|
42
|
+
# === Parameters
|
43
|
+
# options(Hash):: A hash containing the following options by token name:
|
44
|
+
#
|
45
|
+
# target(Object):: Object defining handler methods to be called (required).
|
46
|
+
#
|
47
|
+
# request_handler(Token):: Token for request handler method name (required).
|
48
|
+
#
|
49
|
+
# request_query(Token):: Token for request query method name if server
|
50
|
+
# needs time to calculate a response (allows event loop to continue until
|
51
|
+
# such time as request_query returns true).
|
52
|
+
#
|
53
|
+
# pipe(IO):: pipe object (required).
|
54
|
+
def initialize(options)
|
55
|
+
raise "Missing required :target" unless @target = options[:target]
|
56
|
+
raise "Missing required :request_handler" unless @request_handler = options[:request_handler]
|
57
|
+
raise "Missing require :pipe" unless @pipe = options[:pipe]
|
58
|
+
@request_query = options[:request_query]
|
59
|
+
@unbound = false
|
60
|
+
@state = CONNECTING_STATE
|
61
|
+
@data = nil
|
62
|
+
end
|
63
|
+
|
64
|
+
# Callback from EM to asynchronously read the pipe stream. Note that this
|
65
|
+
# callback mechanism is deprecated after EM v0.12.8
|
66
|
+
def notify_readable
|
67
|
+
if @state == RESPONDING_STATE || @pipe.wait(WAIT_SLEEP_DELAY_MSECS)
|
68
|
+
if @pipe.pending?
|
69
|
+
handle_pending
|
70
|
+
else
|
71
|
+
handle_non_pending
|
72
|
+
end
|
73
|
+
|
74
|
+
# sleep a little to allow asynchronous I/O time to complete and
|
75
|
+
# avoid busy looping.
|
76
|
+
sleep ASYNC_IO_SLEEP_DELAY_MSECS
|
77
|
+
end
|
78
|
+
rescue Exception => e
|
79
|
+
RightScale::Log.error("Failed to send data to Powershell", e, :trace)
|
80
|
+
(disconnect rescue nil) if @state != CONNECTING_STATE
|
81
|
+
end
|
82
|
+
|
83
|
+
# Callback from EM to receive data, which we also use to handle the
|
84
|
+
# asynchronous data we read ourselves.
|
85
|
+
def receive_data(data)
|
86
|
+
# automagically append a newlineto make it easier to parse response.
|
87
|
+
result = @target.method(@request_handler).call(data)
|
88
|
+
result += "\n" unless result[-1] == "\n"[0]
|
89
|
+
return result
|
90
|
+
end
|
91
|
+
|
92
|
+
# Callback from EM to unbind.
|
93
|
+
def unbind
|
94
|
+
Log.debug("unbound")
|
95
|
+
@pipe.close rescue nil
|
96
|
+
@connected = false
|
97
|
+
@pipe = nil
|
98
|
+
@unbound = true
|
99
|
+
end
|
100
|
+
|
101
|
+
# Forces detachment of the handler unless already unbound.
|
102
|
+
def force_detach
|
103
|
+
# No need to use next tick to prevent issue in EM where
|
104
|
+
# descriptors list gets out-of-sync when calling detach
|
105
|
+
# in an unbind callback
|
106
|
+
detach unless @unbound
|
107
|
+
end
|
108
|
+
|
109
|
+
protected
|
110
|
+
|
111
|
+
# Handles any pending I/O from asynchronous pipe server.
|
112
|
+
def handle_pending
|
113
|
+
case @state
|
114
|
+
when CONNECTING_STATE
|
115
|
+
Log.debug("connection pending")
|
116
|
+
connected
|
117
|
+
if @pipe.read
|
118
|
+
consume_pipe_buffer if not @pipe.pending?
|
119
|
+
else
|
120
|
+
disconnect
|
121
|
+
end
|
122
|
+
when READING_STATE
|
123
|
+
Log.debug("read pending")
|
124
|
+
if @pipe.transferred == 0
|
125
|
+
disconnect
|
126
|
+
else
|
127
|
+
consume_pipe_buffer
|
128
|
+
end
|
129
|
+
when RESPONDING_STATE
|
130
|
+
responding
|
131
|
+
when WRITING_STATE
|
132
|
+
Log.debug("write pending")
|
133
|
+
if @pipe.transferred >= @pipe.size
|
134
|
+
write_complete
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Handles state progression when there is no pending I/O.
|
140
|
+
def handle_non_pending
|
141
|
+
case @state
|
142
|
+
when CONNECTING_STATE
|
143
|
+
Log.debug("waiting for connection")
|
144
|
+
if @pipe.connect
|
145
|
+
connected
|
146
|
+
end
|
147
|
+
when READING_STATE
|
148
|
+
Log.debug("still reading request")
|
149
|
+
if @pipe.read
|
150
|
+
consume_pipe_buffer if not @pipe.pending?
|
151
|
+
else
|
152
|
+
disconnect
|
153
|
+
end
|
154
|
+
when RESPONDING_STATE
|
155
|
+
responding
|
156
|
+
when WRITING_STATE
|
157
|
+
Log.debug("done writing request")
|
158
|
+
write_complete
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Acknowledges client connected by changing to reading state.
|
163
|
+
def connected
|
164
|
+
Log.debug("connected")
|
165
|
+
|
166
|
+
# sleep a little to allow asynchronous I/O time to complete and
|
167
|
+
# avoid busy looping before reading from pipe.
|
168
|
+
sleep ASYNC_IO_SLEEP_DELAY_MSECS
|
169
|
+
@state = READING_STATE
|
170
|
+
end
|
171
|
+
|
172
|
+
# Acknowledges request received by invoking EM receive_data method.
|
173
|
+
def read_complete
|
174
|
+
Log.debug("read_complete")
|
175
|
+
if @data && @data.length > 0
|
176
|
+
Log.debug("received: #{@data}")
|
177
|
+
@state = RESPONDING_STATE
|
178
|
+
else
|
179
|
+
disconnect
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Determines if the server implementation requires a callback to see if
|
184
|
+
# a response is available of if the response must be delayed. In the latter
|
185
|
+
# case, the event machine is allowed to continue until the request_query
|
186
|
+
# method returns true.
|
187
|
+
def responding
|
188
|
+
respond if (@request_query.nil? || @target.method(@request_query).call(@data))
|
189
|
+
end
|
190
|
+
|
191
|
+
# Asks the server implementation for the calculated response and puts it
|
192
|
+
# on the wire.
|
193
|
+
def respond
|
194
|
+
response = receive_data(@data)
|
195
|
+
@data = nil
|
196
|
+
if response && response.length > 0
|
197
|
+
Log.debug("writing response = #{response}")
|
198
|
+
if @pipe.write(response)
|
199
|
+
if @pipe.pending?
|
200
|
+
@state = WRITING_STATE
|
201
|
+
else
|
202
|
+
write_complete
|
203
|
+
end
|
204
|
+
else
|
205
|
+
disconnect
|
206
|
+
end
|
207
|
+
else
|
208
|
+
disconnect
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Acknowledges response sent by disconnecting and waiting for next client.
|
213
|
+
def write_complete
|
214
|
+
Log.debug("write_complete")
|
215
|
+
disconnect
|
216
|
+
end
|
217
|
+
|
218
|
+
# Disconnects from client and resumes waiting for next client.
|
219
|
+
def disconnect
|
220
|
+
Log.debug("disconnect")
|
221
|
+
@pipe.disconnect
|
222
|
+
@state = CONNECTING_STATE
|
223
|
+
@data = nil
|
224
|
+
end
|
225
|
+
|
226
|
+
# Consumes the current contents of the pipe buffer.
|
227
|
+
def consume_pipe_buffer
|
228
|
+
buffer = @pipe.buffer.clone
|
229
|
+
Log.debug("before consume @data = #{@data}")
|
230
|
+
if @data
|
231
|
+
@data += buffer
|
232
|
+
else
|
233
|
+
@data = buffer
|
234
|
+
end
|
235
|
+
Log.debug("after consume @data = #{@data}")
|
236
|
+
|
237
|
+
# newline delimits each complete request. the pending flag is not an
|
238
|
+
# indication that the complete request has been received because the
|
239
|
+
# complete request can be buffered in memory and not be "pending".
|
240
|
+
if buffer.index("\n")
|
241
|
+
read_complete
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Provides a generic Windows named pipe server based on eventmachine.
|
247
|
+
class PipeServer < ::Win32::Pipe::Server
|
248
|
+
|
249
|
+
# Hack which allows eventmachine to schedule I/O for this non-Ruby IO
|
250
|
+
# object. EM needs a real file number, so this method uses a temporary
|
251
|
+
# file.
|
252
|
+
#
|
253
|
+
# === Returns
|
254
|
+
# fileno(Integer):: temporary file's file number.
|
255
|
+
def fileno
|
256
|
+
@temp_file = Tempfile.new("RS-pipe-server") unless @temp_file
|
257
|
+
return @temp_file.fileno
|
258
|
+
end
|
259
|
+
|
260
|
+
# Hack which fixes a bug with pending write never resetting pending_io
|
261
|
+
# flag, causing state machine never to reenter waiting state. also resets
|
262
|
+
# buffer which can be set to a small size by a tiny overlapped I/O
|
263
|
+
# operation.
|
264
|
+
def disconnect
|
265
|
+
@pending_io = false
|
266
|
+
@buffer = 0.chr * PIPE_BUFFER_SIZE
|
267
|
+
super
|
268
|
+
end
|
269
|
+
|
270
|
+
# Closes temporary file before closing pipe.
|
271
|
+
def close
|
272
|
+
if @temp_file
|
273
|
+
@temp_file.close
|
274
|
+
@temp_file = nil
|
275
|
+
end
|
276
|
+
super.close
|
277
|
+
end
|
278
|
+
|
279
|
+
end
|
280
|
+
|
281
|
+
end
|
282
|
+
|
283
|
+
end
|