opswalrus 1.0.8 → 1.0.10
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.
- checksums.yaml +4 -4
- data/CNAME +1 -0
- data/Gemfile.lock +1 -1
- data/README.md +29 -16
- data/lib/opswalrus/app.rb +21 -7
- data/lib/opswalrus/bootstrap.sh +5 -0
- data/lib/opswalrus/cli.rb +16 -15
- data/lib/opswalrus/host.rb +115 -71
- data/lib/opswalrus/invocation.rb +446 -0
- data/lib/opswalrus/operation_runner.rb +3 -3
- data/lib/opswalrus/ops_file.rb +71 -32
- data/lib/opswalrus/ops_file_script.rb +55 -473
- data/lib/opswalrus/ops_file_script_dsl.rb +297 -0
- data/lib/opswalrus/patches.rb +1 -0
- data/lib/opswalrus/runtime_environment.rb +40 -9
- data/lib/opswalrus/sshkit_ext.rb +6 -3
- data/lib/opswalrus/version.rb +1 -1
- data/opswalrus.gemspec +1 -1
- metadata +5 -2
@@ -1,337 +1,30 @@
|
|
1
|
-
require 'json'
|
2
1
|
require 'set'
|
3
|
-
|
4
|
-
require 'socket'
|
5
|
-
require 'stringio'
|
6
|
-
|
7
|
-
# require 'ed25519'
|
8
|
-
require 'sshkit'
|
9
|
-
require 'sshkit/dsl'
|
10
|
-
|
11
|
-
require_relative 'host'
|
12
|
-
require_relative 'sshkit_ext'
|
13
|
-
require_relative 'walrus_lang'
|
2
|
+
require_relative 'ops_file_script_dsl'
|
14
3
|
|
15
4
|
module OpsWalrus
|
16
|
-
class ArrayOrHashNavigationProxy
|
17
|
-
def initialize(array_or_hash)
|
18
|
-
@obj = array_or_hash
|
19
|
-
end
|
20
|
-
def [](index, *args, **kwargs, &block)
|
21
|
-
@obj.method(:[]).call(index, *args, **kwargs, &block)
|
22
|
-
end
|
23
|
-
def respond_to_missing?(method, *)
|
24
|
-
@obj.is_a?(Hash) && @obj.respond_to?(method)
|
25
|
-
end
|
26
|
-
def method_missing(name, *args, **kwargs, &block)
|
27
|
-
case @obj
|
28
|
-
when Array
|
29
|
-
@obj.method(name).call(*args, **kwargs, &block)
|
30
|
-
when Hash
|
31
|
-
if @obj.respond_to?(name)
|
32
|
-
@obj.method(name).call(*args, **kwargs, &block)
|
33
|
-
else
|
34
|
-
value = self[name.to_s]
|
35
|
-
case value
|
36
|
-
when Array, Hash
|
37
|
-
ArrayOrHashNavigationProxy.new(value)
|
38
|
-
else
|
39
|
-
value
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
class Params
|
47
|
-
# params : Hash
|
48
|
-
def initialize(params)
|
49
|
-
@params = params
|
50
|
-
end
|
51
|
-
|
52
|
-
def [](key)
|
53
|
-
key = key.to_s if key.is_a? Symbol
|
54
|
-
@params[key]
|
55
|
-
end
|
56
|
-
|
57
|
-
def dig(*keys)
|
58
|
-
# keys = keys.map {|key| key.is_a?(Integer) ? key : key.to_s }
|
59
|
-
@params.dig(*keys)
|
60
|
-
end
|
61
|
-
|
62
|
-
def method_missing(name, *args, **kwargs, &block)
|
63
|
-
if @params.respond_to?(name)
|
64
|
-
@params.method(name).call(*args, **kwargs, &block)
|
65
|
-
else
|
66
|
-
value = self[name]
|
67
|
-
case value
|
68
|
-
when Array, Hash
|
69
|
-
ArrayOrHashNavigationProxy.new(value)
|
70
|
-
else
|
71
|
-
value
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
class Env
|
78
|
-
# env : Hash
|
79
|
-
def initialize(env)
|
80
|
-
@env = env
|
81
|
-
end
|
82
|
-
|
83
|
-
def [](key)
|
84
|
-
key = key.to_s if key.is_a? Symbol
|
85
|
-
@env[key]
|
86
|
-
end
|
87
|
-
|
88
|
-
def dig(*keys)
|
89
|
-
keys = keys.map {|key| key.is_a?(Integer) ? key : key.to_s }
|
90
|
-
@env.dig(*keys)
|
91
|
-
end
|
92
|
-
|
93
|
-
def method_missing(name, *args, **kwargs, &block)
|
94
|
-
if @env.respond_to?(name)
|
95
|
-
@env.method(name).call(*args, **kwargs, &block)
|
96
|
-
else
|
97
|
-
value = self[name]
|
98
|
-
case value
|
99
|
-
when Array, Hash
|
100
|
-
ArrayOrHashNavigationProxy.new(value)
|
101
|
-
else
|
102
|
-
value
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# BootstrapLinuxHostShellScript = <<~SCRIPT
|
109
|
-
# #!/usr/bin/env bash
|
110
|
-
# ...
|
111
|
-
# SCRIPT
|
112
|
-
|
113
|
-
module DSL
|
114
|
-
def ssh(*args, **kwargs, &block)
|
115
|
-
host_proxy_class = @ops_file_script.host_proxy_class
|
116
|
-
hosts = inventory(*args, **kwargs).map {|host| host_proxy_class.new(host) }
|
117
|
-
sshkit_hosts = hosts.map(&:sshkit_host)
|
118
|
-
sshkit_host_to_ops_host_map = sshkit_hosts.zip(hosts).to_h
|
119
|
-
runtime_env = @runtime_env
|
120
|
-
local_host = self
|
121
|
-
# bootstrap_shell_script = BootstrapLinuxHostShellScript
|
122
|
-
# on sshkit_hosts do |sshkit_host|
|
123
|
-
SSHKit::Coordinator.new(sshkit_hosts).each(in: kwargs[:in] || :parallel) do |sshkit_host|
|
124
|
-
|
125
|
-
# in this context, self is an instance of one of the subclasses of SSHKit::Backend::Abstract, e.g. SSHKit::Backend::Netssh
|
126
|
-
|
127
|
-
host = sshkit_host_to_ops_host_map[sshkit_host]
|
128
|
-
# puts "#{host.alias} / #{host}:"
|
129
|
-
|
130
|
-
begin
|
131
|
-
host.set_runtime_env(runtime_env)
|
132
|
-
host.set_ssh_session_connection(self) # self is an instance of one of the subclasses of SSHKit::Backend::Abstract, e.g. SSHKit::Backend::Netssh
|
133
|
-
|
134
|
-
# copy over bootstrap shell script
|
135
|
-
# io = StringIO.new(bootstrap_shell_script)
|
136
|
-
io = File.open(__FILE__.to_pathname.dirname.join("bootstrap.sh"))
|
137
|
-
upload_success = host.upload(io, "tmpopsbootstrap.sh")
|
138
|
-
io.close
|
139
|
-
raise Error, "Unable to upload bootstrap shell script to remote host" unless upload_success
|
140
|
-
host.execute(:chmod, "755", "tmpopsbootstrap.sh")
|
141
|
-
host.execute(:sh, "tmpopsbootstrap.sh")
|
142
|
-
|
143
|
-
# copy over ops bundle zip file
|
144
|
-
zip_bundle_path = runtime_env.zip_bundle_path
|
145
|
-
upload_success = host.upload(zip_bundle_path, "tmpops.zip")
|
146
|
-
raise Error, "Unable to upload ops bundle to remote host" unless upload_success
|
147
|
-
|
148
|
-
stdout, stderr, exit_status = host.run_ops(:bundle, "unzip tmpops.zip", in_bundle_root_dir: false)
|
149
|
-
raise Error, "Unable to unzip ops bundle on remote host" unless exit_status == 0
|
150
|
-
tmp_bundle_root_dir = stdout.strip
|
151
|
-
host.set_ssh_session_tmp_bundle_root_dir(tmp_bundle_root_dir)
|
152
|
-
|
153
|
-
# we run the block in the context of the host, s.t. `self` within the block evaluates to `host`
|
154
|
-
retval = host.instance_exec(local_host, &block) # host is passed as the argument to the block
|
155
|
-
|
156
|
-
puts retval.inspect
|
157
|
-
|
158
|
-
# cleanup
|
159
|
-
if tmp_bundle_root_dir =~ /tmp/ # sanity check the temp path before we blow away something we don't intend
|
160
|
-
host.execute(:rm, "-rf", "tmpopsbootstrap.sh", "tmpops.zip", tmp_bundle_root_dir)
|
161
|
-
else
|
162
|
-
host.execute(:rm, "-rf", "tmpopsbootstrap.sh", "tmpops.zip")
|
163
|
-
end
|
164
|
-
|
165
|
-
retval
|
166
|
-
rescue SSHKit::Command::Failed => e
|
167
|
-
puts "[!] Command failed:"
|
168
|
-
puts e.message
|
169
|
-
rescue Net::SSH::ConnectionTimeout
|
170
|
-
puts "[!] The host '#{host}' not alive!"
|
171
|
-
rescue Net::SSH::Timeout
|
172
|
-
puts "[!] The host '#{host}' disconnected/timeouted unexpectedly!"
|
173
|
-
rescue Errno::ECONNREFUSED
|
174
|
-
puts "[!] Incorrect port #{port} for #{host}"
|
175
|
-
rescue Net::SSH::HostKeyMismatch => e
|
176
|
-
puts "[!] The host fingerprint does not match the last observed fingerprint for #{host}"
|
177
|
-
puts e.message
|
178
|
-
puts "You might try `ssh-keygen -f ~/.ssh/known_hosts -R \"#{host}\"`"
|
179
|
-
rescue Net::SSH::AuthenticationFailed
|
180
|
-
puts "Wrong Password: #{host} | #{user}:#{password}"
|
181
|
-
rescue Net::SSH::Authentication::DisallowedMethod
|
182
|
-
puts "[!] The host '#{host}' doesn't accept password authentication method."
|
183
|
-
rescue Errno::EHOSTUNREACH => e
|
184
|
-
puts "[!] The host '#{host}' is unreachable"
|
185
|
-
rescue => e
|
186
|
-
puts e.class
|
187
|
-
puts e.message
|
188
|
-
# puts e.backtrace.join("\n")
|
189
|
-
ensure
|
190
|
-
host.clear_ssh_session
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
def inventory(*args, **kwargs)
|
196
|
-
tags = args.map(&:to_s)
|
197
|
-
|
198
|
-
kwargs = kwargs.transform_keys(&:to_s)
|
199
|
-
tags.concat(kwargs["tags"]) if kwargs["tags"]
|
200
|
-
|
201
|
-
@runtime_env.app.inventory(tags)
|
202
|
-
end
|
203
|
-
|
204
|
-
def exit(exit_status, message = nil)
|
205
|
-
if message
|
206
|
-
puts message
|
207
|
-
end
|
208
|
-
result = if exit_status == 0
|
209
|
-
Invocation::Success.new(nil)
|
210
|
-
else
|
211
|
-
Invocation::Error.new(nil, exit_status)
|
212
|
-
end
|
213
|
-
throw :exit_now, result
|
214
|
-
end
|
215
|
-
|
216
|
-
def env(*keys)
|
217
|
-
keys = keys.map(&:to_s)
|
218
|
-
if keys.empty?
|
219
|
-
@env
|
220
|
-
else
|
221
|
-
@env.dig(*keys)
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
# currently, import may only be used to import a package that is referenced in the script's package file
|
226
|
-
# I may decide to extend this to work with dynamic package references
|
227
|
-
#
|
228
|
-
# local_package_name is the local package name defined for the package dependency that is attempting to be referenced
|
229
|
-
def import(local_package_name)
|
230
|
-
local_package_name = local_package_name.to_s
|
231
|
-
package_reference = @ops_file_script.ops_file.package_file&.dependency(local_package_name)
|
232
|
-
raise Error, "Unknown package reference: #{local_package_name}" unless package_reference
|
233
|
-
import_reference = PackageDependencyReference.new(local_package_name, package_reference)
|
234
|
-
# puts "import: #{import_reference.inspect}"
|
235
|
-
@runtime_env.resolve_import_reference(@ops_file_script.ops_file, import_reference)
|
236
|
-
end
|
237
|
-
|
238
|
-
def params(*keys, default: nil)
|
239
|
-
keys = keys.map(&:to_s)
|
240
|
-
if keys.empty?
|
241
|
-
@params
|
242
|
-
else
|
243
|
-
@params.dig(*keys) || default
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
# returns the stdout from the command
|
248
|
-
def sh(desc_or_cmd = nil, cmd = nil, input: nil, &block)
|
249
|
-
out, err, status = *shell!(desc_or_cmd, cmd, block, input: input)
|
250
|
-
out
|
251
|
-
end
|
252
|
-
|
253
|
-
# returns the tuple: [stdout, stderr, exit_status]
|
254
|
-
def shell(desc_or_cmd = nil, cmd = nil, input: nil, &block)
|
255
|
-
shell!(desc_or_cmd, cmd, block, input: input)
|
256
|
-
end
|
257
|
-
|
258
|
-
# returns the tuple: [stdout, stderr, exit_status]
|
259
|
-
def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil)
|
260
|
-
# description = nil
|
261
|
-
|
262
|
-
return ["", "", 0] if !desc_or_cmd && !cmd && !block # we were told to do nothing; like hitting enter at the bash prompt; we can do nothing successfully
|
263
|
-
|
264
|
-
description = desc_or_cmd if cmd || block
|
265
|
-
cmd = block.call if block
|
266
|
-
cmd ||= desc_or_cmd
|
267
|
-
|
268
|
-
cmd = WalrusLang.render(cmd, block.binding) if block && cmd =~ /{{.*}}/
|
269
|
-
|
270
|
-
#cmd = Shellwords.escape(cmd)
|
271
|
-
|
272
|
-
# puts "shell! self: #{self.inspect}"
|
273
|
-
|
274
|
-
print "[#{@runtime_env.local_hostname}] "
|
275
|
-
print "#{description}: " if description
|
276
|
-
puts cmd
|
277
|
-
|
278
|
-
return unless cmd && !cmd.strip.empty?
|
279
|
-
|
280
|
-
# sudo_password = @runtime_env.sudo_password
|
281
|
-
# sudo_password &&= sudo_password.gsub(/\n+$/,'') # remove trailing newlines from sudo_password
|
282
|
-
|
283
|
-
# puts "shell: #{cmd}"
|
284
|
-
# puts "shell: #{cmd.inspect}"
|
285
|
-
# puts "sudo_password: #{sudo_password}"
|
286
|
-
|
287
|
-
# sshkit_cmd = SSHKit::Backend::LocalNonBlocking.new {
|
288
|
-
# sshkit_cmd = SSHKit::Backend::LocalPty.new {
|
289
|
-
# sshkit_cmd = backend.execute_cmd(cmd, interaction_handler: SudoPasswordMapper.new(sudo_password).interaction_handler, verbosity: :info)
|
290
|
-
# execute_cmd(cmd, interaction_handler: SudoPromptInteractionHandler.new, verbosity: :info)
|
291
|
-
# }.run
|
292
|
-
|
293
|
-
sshkit_cmd = @runtime_env.handle_input(input) do |interaction_handler|
|
294
|
-
backend.execute_cmd(cmd, interaction_handler: interaction_handler, verbosity: :info)
|
295
|
-
end
|
296
|
-
|
297
|
-
[sshkit_cmd.full_stdout, sshkit_cmd.full_stderr, sshkit_cmd.exit_status]
|
298
|
-
end
|
299
|
-
|
300
|
-
# def init_brew
|
301
|
-
# execute('eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"')
|
302
|
-
# end
|
303
|
-
|
304
|
-
end
|
305
5
|
|
306
6
|
class OpsFileScript
|
307
|
-
attr_accessor :ops_file
|
308
7
|
|
309
|
-
def
|
310
|
-
|
311
|
-
@ruby_script = ruby_script
|
312
|
-
@invocation_class = define_invocation_class
|
313
|
-
@host_proxy_class = define_host_proxy_class
|
314
|
-
end
|
8
|
+
def self.define_for(ops_file, ruby_script)
|
9
|
+
klass = Class.new(OpsFileScript)
|
315
10
|
|
316
|
-
|
317
|
-
klass = Class.new(Invocation)
|
11
|
+
# puts "OpsFileScript.define_for(#{ops_file.to_s}, #{ruby_script.to_s})"
|
318
12
|
|
319
13
|
methods_defined = Set.new
|
320
14
|
|
321
|
-
# define methods for
|
15
|
+
# define methods for the OpsFile's local_symbol_table: local imports and private lib directory
|
322
16
|
ops_file.local_symbol_table.each do |symbol_name, import_reference|
|
323
17
|
unless methods_defined.include? symbol_name
|
18
|
+
# puts "defining method for local symbol table entry: #{symbol_name}"
|
324
19
|
klass.define_method(symbol_name) do |*args, **kwargs, &block|
|
325
|
-
# puts "
|
326
|
-
|
327
|
-
# puts
|
328
|
-
|
329
|
-
namespace_or_ops_file = @runtime_env.resolve_import_reference(@ops_file_script.ops_file, import_reference)
|
330
|
-
# puts namespace_or_ops_file.inspect
|
331
|
-
# puts "0" * 80
|
20
|
+
# puts "resolving local symbol table entry: #{symbol_name}"
|
21
|
+
namespace_or_ops_file = @runtime_env.resolve_import_reference(ops_file, import_reference)
|
22
|
+
# puts "namespace_or_ops_file=#{namespace_or_ops_file.to_s}"
|
23
|
+
|
332
24
|
case namespace_or_ops_file
|
333
25
|
when Namespace
|
334
26
|
namespace_or_ops_file
|
27
|
+
namespace_or_ops_file._invoke_if_namespace_has_ops_file_of_same_name(*args, **kwargs)
|
335
28
|
when OpsFile
|
336
29
|
params_hash = namespace_or_ops_file.build_params_hash(*args, **kwargs)
|
337
30
|
namespace_or_ops_file.invoke(@runtime_env, params_hash)
|
@@ -342,22 +35,23 @@ module OpsWalrus
|
|
342
35
|
end
|
343
36
|
|
344
37
|
# define methods for every Namespace or OpsFile within the namespace that the OpsFile resides within
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
38
|
+
sibling_symbol_table_names = Set.new
|
39
|
+
sibling_symbol_table_names |= ops_file.dirname.glob("*.ops").map {|ops_file_path| ops_file_path.basename(".ops").to_s } # OpsFiles
|
40
|
+
sibling_symbol_table_names |= ops_file.dirname.glob("*").select(&:directory?).map {|dir_path| dir_path.basename.to_s } # Namespaces
|
41
|
+
# puts "sibling_symbol_table_names=#{sibling_symbol_table_names}"
|
42
|
+
# puts "methods_defined=#{methods_defined}"
|
43
|
+
sibling_symbol_table_names.each do |symbol_name|
|
349
44
|
unless methods_defined.include? symbol_name
|
45
|
+
# puts "defining method for implicit imports: #{symbol_name}"
|
350
46
|
klass.define_method(symbol_name) do |*args, **kwargs, &block|
|
351
|
-
# puts "
|
352
|
-
|
353
|
-
# puts
|
354
|
-
|
355
|
-
namespace_or_ops_file = @runtime_env.resolve_sibling_symbol(@ops_file_script.ops_file, symbol_name)
|
356
|
-
# puts namespace_or_ops_file.inspect
|
357
|
-
# puts "0" * 80
|
47
|
+
# puts "resolving implicit import: #{symbol_name}"
|
48
|
+
namespace_or_ops_file = @runtime_env.resolve_sibling_symbol(ops_file, symbol_name)
|
49
|
+
# puts "namespace_or_ops_file=#{namespace_or_ops_file.to_s}"
|
50
|
+
|
358
51
|
case namespace_or_ops_file
|
359
52
|
when Namespace
|
360
53
|
namespace_or_ops_file
|
54
|
+
namespace_or_ops_file._invoke_if_namespace_has_ops_file_of_same_name(*args, **kwargs)
|
361
55
|
when OpsFile
|
362
56
|
params_hash = namespace_or_ops_file.build_params_hash(*args, **kwargs)
|
363
57
|
namespace_or_ops_file.invoke(@runtime_env, params_hash)
|
@@ -367,116 +61,38 @@ module OpsWalrus
|
|
367
61
|
end
|
368
62
|
end
|
369
63
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
#
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
# we know we're dealing with a package dependency reference, so we want to run an ops file contained within the bundle directory,
|
385
|
-
# therefore, we want to reference the specified ops file with respect to the bundle dir
|
386
|
-
when PackageDependencyReference
|
387
|
-
HostProxyOpsFileInvocationBuilder.new(self, true)
|
388
|
-
|
389
|
-
# we know we're dealing with a directory reference or OpsFile reference outside of the bundle dir, so we want to reference
|
390
|
-
# the specified ops file with respect to the root directory, and not with respect to the bundle dir
|
391
|
-
when DirectoryReference, OpsFileReference
|
392
|
-
HostProxyOpsFileInvocationBuilder.new(self, false)
|
393
|
-
end
|
394
|
-
|
395
|
-
invocation_builder.send(symbol_name, *args, **kwargs, &block)
|
396
|
-
end
|
397
|
-
methods_defined << symbol_name
|
64
|
+
# the evaluation context needs to be a module with all of the following:
|
65
|
+
# - OpsFileScriptDSL methods
|
66
|
+
# - @runtime_env
|
67
|
+
# - @params
|
68
|
+
# - #host_proxy_class
|
69
|
+
# - #backend
|
70
|
+
# - #debug?
|
71
|
+
# - #verbose?
|
72
|
+
# - all the dynamically defined methods in the subclass of Invocation
|
73
|
+
invoke_method_definition = <<~INVOKE_METHOD
|
74
|
+
def _invoke(runtime_env, params_hash)
|
75
|
+
@runtime_env = runtime_env
|
76
|
+
@params = InvocationParams.new(params_hash)
|
77
|
+
#{ruby_script}
|
398
78
|
end
|
399
|
-
|
79
|
+
INVOKE_METHOD
|
400
80
|
|
401
|
-
|
402
|
-
|
403
|
-
sibling_symbol_table |= ops_file.dirname.glob("*.ops").map {|ops_file_path| ops_file_path.basename(".ops").to_s } # OpsFiles
|
404
|
-
sibling_symbol_table |= ops_file.dirname.glob("*").select(&:directory?).map {|dir_path| dir_path.basename.to_s } # Namespaces
|
405
|
-
sibling_symbol_table.each do |symbol_name|
|
406
|
-
unless methods_defined.include? symbol_name
|
407
|
-
# puts "2. defining: #{symbol_name}(...)"
|
408
|
-
klass.define_method(symbol_name) do |*args, **kwargs, &block|
|
409
|
-
invocation_builder = HostProxyOpsFileInvocationBuilder.new(self, false)
|
410
|
-
invocation_builder.invoke(symbol_name, *args, **kwargs, &block)
|
411
|
-
end
|
412
|
-
methods_defined << symbol_name
|
413
|
-
end
|
414
|
-
end
|
81
|
+
invoke_method_line_count_prior_to_ruby_script_from_ops_file = 3
|
82
|
+
klass.module_eval(invoke_method_definition, ops_file.ops_file_path.to_s, ops_file.script_line_offset - invoke_method_line_count_prior_to_ruby_script_from_ops_file)
|
415
83
|
|
416
84
|
klass
|
417
85
|
end
|
418
86
|
|
419
|
-
def host_proxy_class
|
420
|
-
@host_proxy_class
|
421
|
-
end
|
422
|
-
|
423
|
-
def script
|
424
|
-
@ruby_script
|
425
|
-
end
|
426
|
-
|
427
|
-
def invoke(runtime_env, params_hash)
|
428
|
-
# Invocation.new(self, runtime_env, params_hash).evaluate
|
429
|
-
# puts "INVOKE" * 10
|
430
|
-
# puts runtime_env.inspect
|
431
|
-
@invocation_class.new(self, runtime_env, params_hash).evaluate
|
432
|
-
end
|
433
|
-
|
434
|
-
def to_s
|
435
|
-
@ruby_script
|
436
|
-
end
|
437
|
-
end
|
438
|
-
|
439
|
-
# An Invocation object represents a stack frame, and the params_hash represents the
|
440
|
-
# arguments that the caller has supplied for that stack frame to reference
|
441
|
-
class Invocation
|
442
|
-
class Result
|
443
|
-
attr_accessor :value
|
444
|
-
attr_accessor :exit_status
|
445
|
-
def initialize(value, exit_status = 0)
|
446
|
-
@value = value
|
447
|
-
@exit_status = exit_status
|
448
|
-
end
|
449
|
-
def success?
|
450
|
-
!failure?
|
451
|
-
end
|
452
|
-
def failure?
|
453
|
-
!success?
|
454
|
-
end
|
455
|
-
end
|
456
|
-
class Success < Result
|
457
|
-
def initialize(value)
|
458
|
-
super(value, 0)
|
459
|
-
end
|
460
|
-
def success?
|
461
|
-
true
|
462
|
-
end
|
463
|
-
end
|
464
|
-
class Error < Result
|
465
|
-
def initialize(value, exit_status = 1)
|
466
|
-
super(value, exit_status == 0 ? 1 : exit_status)
|
467
|
-
end
|
468
|
-
def failure?
|
469
|
-
true
|
470
|
-
end
|
471
|
-
end
|
472
87
|
|
88
|
+
include OpsFileScriptDSL
|
473
89
|
|
474
|
-
|
90
|
+
attr_accessor :ops_file
|
475
91
|
|
476
|
-
def initialize(
|
477
|
-
@
|
478
|
-
@
|
479
|
-
@
|
92
|
+
def initialize(ops_file, ruby_script)
|
93
|
+
@ops_file = ops_file
|
94
|
+
@script = ruby_script
|
95
|
+
@runtime_env = nil # this is set at the very first line of #_invoke
|
480
96
|
end
|
481
97
|
|
482
98
|
def backend
|
@@ -491,52 +107,18 @@ module OpsWalrus
|
|
491
107
|
@runtime_env.verbose?
|
492
108
|
end
|
493
109
|
|
494
|
-
def
|
495
|
-
|
496
|
-
eval(@ops_file_script.script, nil, @ops_file_script.ops_file.ops_file_path.to_s, @ops_file_script.ops_file.script_line_offset)
|
497
|
-
# end
|
110
|
+
def host_proxy_class
|
111
|
+
@ops_file.host_proxy_class
|
498
112
|
end
|
499
113
|
|
500
|
-
#
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
# end
|
505
|
-
# rescue => e
|
506
|
-
# $stderr.puts "Error: Ops script crashed."
|
507
|
-
# $stderr.puts e.message
|
508
|
-
# $stderr.puts e.backtrace.join("\n")
|
509
|
-
# Error.new(e)
|
510
|
-
# end
|
511
|
-
|
512
|
-
# if ruby_script_return.is_a? Result
|
513
|
-
# ruby_script_return
|
514
|
-
# else
|
515
|
-
# Success.new(ruby_script_return)
|
516
|
-
# end
|
517
|
-
# end
|
518
|
-
|
519
|
-
# def method_missing(name, *args, **kwargs, &block)
|
520
|
-
# puts "1" * 80
|
521
|
-
# import_reference = @ops_file_script.ops_file.resolve_import(name)
|
522
|
-
# if import_reference
|
523
|
-
# puts "2" * 80
|
524
|
-
# resolved_value = @runtime_env.resolve_import_reference(@ops_file_script.ops_file, import_reference)
|
525
|
-
# return resolved_value if resolved_value
|
526
|
-
# end
|
114
|
+
# The _invoke method is dynamically defined as part of OpsFileScript.define_for
|
115
|
+
def _invoke(runtime_env, params_hash)
|
116
|
+
raise "Not implemented in base class."
|
117
|
+
end
|
527
118
|
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
# puts "4" * 80
|
532
|
-
# namespace_or_ops_file
|
533
|
-
# when OpsFile
|
534
|
-
# puts "5" * 80
|
535
|
-
# namespace_or_ops_file.invoke(@runtime_env, *args, **kwargs, &block)
|
536
|
-
# else
|
537
|
-
# raise NoMethodError, "No method named '#{name}'"
|
538
|
-
# end
|
539
|
-
# end
|
119
|
+
def to_s
|
120
|
+
@script
|
121
|
+
end
|
540
122
|
end
|
541
123
|
|
542
124
|
end
|