opswalrus 1.0.12 → 1.0.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,446 +1,134 @@
1
- # require 'json'
2
- # require 'set'
3
- # require 'shellwords'
4
- # require 'socket'
5
- # require 'stringio'
6
1
 
7
- # require 'sshkit'
8
- # require 'sshkit/dsl'
9
-
10
- # require_relative 'host'
11
- # require_relative 'sshkit_ext'
12
- # require_relative 'walrus_lang'
13
-
14
- # module OpsWalrus
15
-
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 InvocationParams
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
-
78
- # # BootstrapLinuxHostShellScript = <<~SCRIPT
79
- # # #!/usr/bin/env bash
80
- # # ...
81
- # # SCRIPT
82
-
83
- # module InvocationDSL
84
- # def ssh(*args, **kwargs, &block)
85
- # host_proxy_class = @ops_file_script.host_proxy_class
86
- # hosts = inventory(*args, **kwargs).map {|host| host_proxy_class.new(host) }
87
- # sshkit_hosts = hosts.map(&:sshkit_host)
88
- # sshkit_host_to_ops_host_map = sshkit_hosts.zip(hosts).to_h
89
- # runtime_env = @runtime_env
90
- # local_host = self
91
- # # bootstrap_shell_script = BootstrapLinuxHostShellScript
92
- # # on sshkit_hosts do |sshkit_host|
93
- # SSHKit::Coordinator.new(sshkit_hosts).each(in: kwargs[:in] || :parallel) do |sshkit_host|
94
-
95
- # # in this context, self is an instance of one of the subclasses of SSHKit::Backend::Abstract, e.g. SSHKit::Backend::Netssh
96
-
97
- # host = sshkit_host_to_ops_host_map[sshkit_host]
98
- # # puts "#{host.alias} / #{host}:"
99
-
100
- # begin
101
- # host.set_runtime_env(runtime_env)
102
- # host.set_ssh_session_connection(self) # self is an instance of one of the subclasses of SSHKit::Backend::Abstract, e.g. SSHKit::Backend::Netssh
103
-
104
- # # copy over bootstrap shell script
105
- # # io = StringIO.new(bootstrap_shell_script)
106
- # io = File.open(__FILE__.to_pathname.dirname.join("bootstrap.sh"))
107
- # upload_success = host.upload(io, "tmpopsbootstrap.sh")
108
- # io.close
109
- # raise Error, "Unable to upload bootstrap shell script to remote host" unless upload_success
110
- # host.execute(:chmod, "755", "tmpopsbootstrap.sh")
111
- # host.execute(:sh, "tmpopsbootstrap.sh")
112
-
113
- # # copy over ops bundle zip file
114
- # zip_bundle_path = runtime_env.zip_bundle_path
115
- # upload_success = host.upload(zip_bundle_path, "tmpops.zip")
116
- # raise Error, "Unable to upload ops bundle to remote host" unless upload_success
117
-
118
- # stdout, stderr, exit_status = host.run_ops(:bundle, "unzip tmpops.zip", in_bundle_root_dir: false)
119
- # raise Error, "Unable to unzip ops bundle on remote host" unless exit_status == 0
120
- # tmp_bundle_root_dir = stdout.strip
121
- # host.set_ssh_session_tmp_bundle_root_dir(tmp_bundle_root_dir)
122
-
123
- # # we run the block in the context of the host, s.t. `self` within the block evaluates to `host`
124
- # retval = host.instance_exec(local_host, &block) # host is passed as the argument to the block
125
-
126
- # # puts retval.inspect
127
-
128
- # # cleanup
129
- # if tmp_bundle_root_dir =~ /tmp/ # sanity check the temp path before we blow away something we don't intend
130
- # host.execute(:rm, "-rf", "tmpopsbootstrap.sh", "tmpops.zip", tmp_bundle_root_dir)
131
- # else
132
- # host.execute(:rm, "-rf", "tmpopsbootstrap.sh", "tmpops.zip")
133
- # end
134
-
135
- # retval
136
- # rescue SSHKit::Command::Failed => e
137
- # puts "[!] Command failed:"
138
- # puts e.message
139
- # rescue Net::SSH::ConnectionTimeout
140
- # puts "[!] The host '#{host}' not alive!"
141
- # rescue Net::SSH::Timeout
142
- # puts "[!] The host '#{host}' disconnected/timeouted unexpectedly!"
143
- # rescue Errno::ECONNREFUSED
144
- # puts "[!] Incorrect port #{port} for #{host}"
145
- # rescue Net::SSH::HostKeyMismatch => e
146
- # puts "[!] The host fingerprint does not match the last observed fingerprint for #{host}"
147
- # puts e.message
148
- # puts "You might try `ssh-keygen -f ~/.ssh/known_hosts -R \"#{host}\"`"
149
- # rescue Net::SSH::AuthenticationFailed
150
- # puts "Wrong Password: #{host} | #{user}:#{password}"
151
- # rescue Net::SSH::Authentication::DisallowedMethod
152
- # puts "[!] The host '#{host}' doesn't accept password authentication method."
153
- # rescue Errno::EHOSTUNREACH => e
154
- # puts "[!] The host '#{host}' is unreachable"
155
- # rescue => e
156
- # puts e.class
157
- # puts e.message
158
- # # puts e.backtrace.join("\n")
159
- # ensure
160
- # host.clear_ssh_session
161
- # end
162
- # end
163
- # end
164
-
165
- # def inventory(*args, **kwargs)
166
- # tags = args.map(&:to_s)
167
-
168
- # kwargs = kwargs.transform_keys(&:to_s)
169
- # tags.concat(kwargs["tags"]) if kwargs["tags"]
170
-
171
- # @runtime_env.app.inventory(tags)
172
- # end
173
-
174
- # def exit(exit_status, message = nil)
175
- # if message
176
- # puts message
177
- # end
178
- # result = if exit_status == 0
179
- # Invocation::Success.new(nil)
180
- # else
181
- # Invocation::Error.new(nil, exit_status)
182
- # end
183
- # throw :exit_now, result
184
- # end
185
-
186
- # def env(*keys)
187
- # keys = keys.map(&:to_s)
188
- # if keys.empty?
189
- # @env
190
- # else
191
- # @env.dig(*keys)
192
- # end
193
- # end
194
-
195
- # # currently, import may only be used to import a package that is referenced in the script's package file
196
- # # I may decide to extend this to work with dynamic package references
197
- # #
198
- # # local_package_name is the local package name defined for the package dependency that is attempting to be referenced
199
- # def import(local_package_name)
200
- # local_package_name = local_package_name.to_s
201
- # package_reference = @ops_file_script.ops_file.package_file&.dependency(local_package_name)
202
- # raise Error, "Unknown package reference: #{local_package_name}" unless package_reference
203
- # import_reference = PackageDependencyReference.new(local_package_name, package_reference)
204
- # # puts "import: #{import_reference.inspect}"
205
- # @runtime_env.resolve_import_reference(@ops_file_script.ops_file, import_reference)
206
- # end
207
-
208
- # def params(*keys, default: nil)
209
- # keys = keys.map(&:to_s)
210
- # if keys.empty?
211
- # @params
212
- # else
213
- # @params.dig(*keys) || default
214
- # end
215
- # end
216
-
217
- # # returns the stdout from the command
218
- # def sh(desc_or_cmd = nil, cmd = nil, input: nil, &block)
219
- # out, err, status = *shell!(desc_or_cmd, cmd, block, input: input)
220
- # out
221
- # end
222
-
223
- # # returns the tuple: [stdout, stderr, exit_status]
224
- # def shell(desc_or_cmd = nil, cmd = nil, input: nil, &block)
225
- # shell!(desc_or_cmd, cmd, block, input: input)
226
- # end
227
-
228
- # # returns the tuple: [stdout, stderr, exit_status]
229
- # def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil)
230
- # # description = nil
231
-
232
- # 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
233
-
234
- # description = desc_or_cmd if cmd || block
235
- # cmd = block.call if block
236
- # cmd ||= desc_or_cmd
237
-
238
- # cmd = WalrusLang.render(cmd, block.binding) if block && cmd =~ /{{.*}}/
239
-
240
- # #cmd = Shellwords.escape(cmd)
241
-
242
- # # puts "shell! self: #{self.inspect}"
243
-
244
- # if App.instance.report_mode?
245
- # print "[#{@runtime_env.local_hostname}] "
246
- # print "#{description}: " if description
247
- # puts cmd
248
- # end
249
-
250
- # return unless cmd && !cmd.strip.empty?
251
-
252
- # sshkit_cmd = @runtime_env.handle_input(input) do |interaction_handler|
253
- # # self is a Module instance that is serving as the evaluation context in an instance of a subclass of an Invocation; see Invocation#evaluate
254
- # backend.execute_cmd(cmd, interaction_handler: interaction_handler, verbosity: :info)
255
- # end
256
-
257
- # [sshkit_cmd.full_stdout, sshkit_cmd.full_stderr, sshkit_cmd.exit_status]
258
- # end
259
-
260
- # # def init_brew
261
- # # execute('eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"')
262
- # # end
263
-
264
- # end
265
-
266
- # # An Invocation object represents a stack frame, and the params_hash represents the
267
- # # arguments that the caller has supplied for that stack frame to reference
268
- # class Invocation
269
- # class Result
270
- # attr_accessor :value
271
- # attr_accessor :exit_status
272
- # def initialize(value, exit_status = 0)
273
- # @value = value
274
- # @exit_status = exit_status
275
- # end
276
- # def success?
277
- # !failure?
278
- # end
279
- # def failure?
280
- # !success?
281
- # end
282
- # end
283
- # class Success < Result
284
- # def initialize(value)
285
- # super(value, 0)
286
- # end
287
- # def success?
288
- # true
289
- # end
290
- # end
291
- # class Error < Result
292
- # def initialize(value, exit_status = 1)
293
- # super(value, exit_status == 0 ? 1 : exit_status)
294
- # end
295
- # def failure?
296
- # true
297
- # end
298
- # end
299
-
300
-
301
- # def self.define_invocation_class(ops_file)
302
- # klass = Class.new(Invocation)
303
-
304
- # methods_defined = Set.new
305
-
306
- # # define methods for every import in the script
307
- # ops_file.local_symbol_table.each do |symbol_name, import_reference|
308
- # unless methods_defined.include? symbol_name
309
- # klass.define_method(symbol_name) do |*args, **kwargs, &block|
310
- # # puts "0" * 80
311
- # # puts "@runtime_env.resolve_import_reference(@ops_file_script.ops_file, #{import_reference.inspect})"
312
- # # puts @ops_file_script.ops_file.ops_file_path
313
- # # puts symbol_name
314
- # namespace_or_ops_file = @runtime_env.resolve_import_reference(@ops_file_script.ops_file, import_reference)
315
- # # puts namespace_or_ops_file.inspect
316
- # # puts "0" * 80
317
- # case namespace_or_ops_file
318
- # when Namespace
319
- # namespace_or_ops_file
320
- # when OpsFile
321
- # params_hash = namespace_or_ops_file.build_params_hash(*args, **kwargs)
322
- # namespace_or_ops_file.invoke(@runtime_env, params_hash)
323
- # end
324
- # end
325
- # methods_defined << symbol_name
326
- # end
327
- # end
328
-
329
- # # define methods for every Namespace or OpsFile within the namespace that the OpsFile resides within
330
- # sibling_symbol_table = Set.new
331
- # sibling_symbol_table |= ops_file.dirname.glob("*.ops").map {|ops_file_path| ops_file_path.basename(".ops").to_s } # OpsFiles
332
- # sibling_symbol_table |= ops_file.dirname.glob("*").select(&:directory?).map {|dir_path| dir_path.basename.to_s } # Namespaces
333
- # sibling_symbol_table.each do |symbol_name|
334
- # unless methods_defined.include? symbol_name
335
- # klass.define_method(symbol_name) do |*args, **kwargs, &block|
336
- # # puts "0" * 80
337
- # # puts "@runtime_env.resolve_symbol(@ops_file_script.ops_file, #{symbol_name})"
338
- # # puts @ops_file_script.ops_file.ops_file_path
339
- # # puts symbol_name
340
- # namespace_or_ops_file = @runtime_env.resolve_sibling_symbol(@ops_file_script.ops_file, symbol_name)
341
- # # puts namespace_or_ops_file.inspect
342
- # # puts "0" * 80
343
- # case namespace_or_ops_file
344
- # when Namespace
345
- # namespace_or_ops_file
346
- # when OpsFile
347
- # params_hash = namespace_or_ops_file.build_params_hash(*args, **kwargs)
348
- # namespace_or_ops_file.invoke(@runtime_env, params_hash)
349
- # end
350
- # end
351
- # methods_defined << symbol_name
352
- # end
353
- # end
354
-
355
- # klass
356
- # end
357
-
358
- # include InvocationDSL
359
-
360
- # def initialize(ops_file_script, runtime_env, params_hash)
361
- # @ops_file_script = ops_file_script
362
- # @runtime_env = runtime_env
363
- # @params = InvocationParams.new(params_hash)
364
- # end
365
-
366
- # def backend
367
- # @runtime_env.pty
368
- # end
369
-
370
- # def debug?
371
- # @runtime_env.debug?
372
- # end
373
-
374
- # def verbose?
375
- # @runtime_env.verbose?
376
- # end
377
-
378
- # # def evaluate
379
- # # # the evaluation context needs to be a module with all of the following:
380
- # # # - InvocationDSL methods
381
- # # # - @ops_file_script
382
- # # # - @runtime_env
383
- # # # - @params
384
- # # # - #backend
385
- # # # - #debug?
386
- # # # - #verbose?
387
- # # # - all the dynamically defined methods in the subclass of Invocation
388
- # # end
389
-
390
- # def evaluate
391
- # eval(@ops_file_script.script, nil, @ops_file_script.ops_file.ops_file_path.to_s, @ops_file_script.ops_file.script_line_offset)
392
- # end
393
-
394
- # # def evaluate
395
- # # ops_file_script = @ops_file_script
396
- # # runtime_env = @runtime_env
397
- # # invocation_params = @params
398
-
399
- # # # we use a Module as the evaluation context instead of this #evaluate method so that classes and other structures may be defined in an .ops file
400
- # # evaluation_context = Module.new
401
- # # evaluation_context.module_exec {
402
- # # include InvocationDSL
403
-
404
- # # @ops_file_script = ops_file_script
405
- # # @runtime_env = runtime_env
406
- # # @params = invocation_params
407
-
408
- # # def backend
409
- # # @runtime_env.pty
410
- # # end
411
-
412
- # # def debug?
413
- # # @runtime_env.debug?
414
- # # end
415
-
416
- # # def verbose?
417
- # # @runtime_env.verbose?
418
- # # end
419
- # # }
420
-
421
- # # evaluation_context.module_eval(@ops_file_script.script, @ops_file_script.ops_file.ops_file_path.to_s, @ops_file_script.ops_file.script_line_offset)
422
- # # end
423
-
424
- # # def method_missing(name, *args, **kwargs, &block)
425
- # # puts "1" * 80
426
- # # import_reference = @ops_file_script.ops_file.resolve_import(name)
427
- # # if import_reference
428
- # # puts "2" * 80
429
- # # resolved_value = @runtime_env.resolve_import_reference(@ops_file_script.ops_file, import_reference)
430
- # # return resolved_value if resolved_value
431
- # # end
432
-
433
- # # puts "3" * 80
434
- # # case namespace_or_ops_file = @runtime_env.resolve_symbol(@ops_file_script.ops_file, name.to_s)
435
- # # when Namespace
436
- # # puts "4" * 80
437
- # # namespace_or_ops_file
438
- # # when OpsFile
439
- # # puts "5" * 80
440
- # # namespace_or_ops_file.invoke(@runtime_env, *args, **kwargs, &block)
441
- # # else
442
- # # raise NoMethodError, "No method named '#{name}'"
443
- # # end
444
- # # end
445
- # end
446
- # end
2
+ module OpsWalrus
3
+
4
+ class ImportInvocationContext
5
+ def _invoke(*args, **kwargs)
6
+ raise "Not implemented in base class"
7
+ end
8
+
9
+ def _invoke_if_namespace_has_ops_file_of_same_name(*args, **kwargs, &block)
10
+ raise "Not implemented in base class"
11
+ end
12
+
13
+ def method_missing(name, *args, **kwargs, &block)
14
+ raise "Not implemented in base class"
15
+ end
16
+ end
17
+
18
+ class RemoteImportInvocationContext < ImportInvocationContext
19
+ def initialize(runtime_env, host_proxy, namespace_or_ops_file, is_invocation_a_call_to_package_in_bundle_dir = false)
20
+ @runtime_env = runtime_env
21
+ @host_proxy = host_proxy
22
+ @initial_namespace_or_ops_file = @namespace_or_ops_file = namespace_or_ops_file
23
+ @is_invocation_a_call_to_package_in_bundle_dir = is_invocation_a_call_to_package_in_bundle_dir
24
+
25
+ initial_method_name = @namespace_or_ops_file.dirname.basename
26
+ @method_chain = [initial_method_name]
27
+ end
28
+
29
+ def _invoke(*args, **kwargs)
30
+ case @namespace_or_ops_file
31
+ when Namespace
32
+ _invoke_if_namespace_has_ops_file_of_same_name(*args, **kwargs)
33
+ when OpsFile
34
+ _invoke_remote(*args, **kwargs)
35
+ end
36
+ end
37
+
38
+ def _invoke_remote(*args, **kwargs)
39
+ # when there are args or kwargs, then the method invocation represents an attempt to run an OpsFile on a remote host,
40
+ # so we want to build up a command and send it to the remote host via HostDSL#run_ops
41
+ @method_chain.unshift(Bundler::BUNDLE_DIR) if @is_invocation_a_call_to_package_in_bundle_dir
42
+
43
+ remote_run_command_args = @method_chain.join(" ")
44
+
45
+ unless args.empty?
46
+ remote_run_command_args << " "
47
+ remote_run_command_args << args.join(" ")
48
+ end
49
+
50
+ unless kwargs.empty?
51
+ remote_run_command_args << " "
52
+ remote_run_command_args << kwargs.map do |k, v|
53
+ case v
54
+ when Array
55
+ v.map {|v_element| "#{k}:#{v_element}" }
56
+ else
57
+ "#{k}:#{v}"
58
+ end
59
+ end.join(" ")
60
+ end
61
+
62
+ @host_proxy.run_ops(:run, "--script", remote_run_command_args)
63
+ end
64
+
65
+ # if this namespace contains an OpsFile of the same name as the namespace, e.g. pkg/install/install.ops, then this
66
+ # method invokes the OpsFile of that same name and returns the result;
67
+ # otherwise we return this namespace object
68
+ def _invoke_if_namespace_has_ops_file_of_same_name(*args, **kwargs, &block)
69
+ method_name = @namespace_or_ops_file.dirname.basename
70
+ resolved_symbol = @namespace_or_ops_file.resolve_symbol(method_name)
71
+ if resolved_symbol.is_a? OpsFile
72
+ _resolve_method_and_invoke(method_name)
73
+ else
74
+ self
75
+ end
76
+ end
77
+
78
+ def _resolve_method_and_invoke(name, *args, **kwargs)
79
+ @method_chain << name.to_s
80
+
81
+ @namespace_or_ops_file = @namespace_or_ops_file.resolve_symbol(name)
82
+ _invoke(*args, **kwargs)
83
+ end
84
+
85
+ def method_missing(name, *args, **kwargs, &block)
86
+ _resolve_method_and_invoke(name, *args, **kwargs)
87
+ end
88
+ end
89
+
90
+ class LocalImportInvocationContext < ImportInvocationContext
91
+ def initialize(runtime_env, namespace_or_ops_file)
92
+ @runtime_env = runtime_env
93
+ @initial_namespace_or_ops_file = @namespace_or_ops_file = namespace_or_ops_file
94
+ end
95
+
96
+ def _invoke(*args, **kwargs)
97
+ case @namespace_or_ops_file
98
+ when Namespace
99
+ _invoke_if_namespace_has_ops_file_of_same_name(*args, **kwargs)
100
+ when OpsFile
101
+ _invoke_local(*args, **kwargs)
102
+ end
103
+ end
104
+
105
+ def _invoke_local(*args, **kwargs)
106
+ params_hash = @namespace_or_ops_file.build_params_hash(*args, **kwargs)
107
+ @namespace_or_ops_file.invoke(@runtime_env, params_hash)
108
+ end
109
+
110
+ # if this namespace contains an OpsFile of the same name as the namespace, e.g. pkg/install/install.ops, then this
111
+ # method invokes the OpsFile of that same name and returns the result;
112
+ # otherwise we return this namespace object
113
+ def _invoke_if_namespace_has_ops_file_of_same_name(*args, **kwargs, &block)
114
+ method_name = @namespace_or_ops_file.dirname.basename
115
+ resolved_symbol = @namespace_or_ops_file.resolve_symbol(method_name)
116
+ if resolved_symbol.is_a? OpsFile
117
+ params_hash = resolved_symbol.build_params_hash(*args, **kwargs)
118
+ resolved_symbol.invoke(@runtime_env, params_hash)
119
+ else
120
+ self
121
+ end
122
+ end
123
+
124
+ def _resolve_method_and_invoke(name, *args, **kwargs)
125
+ @namespace_or_ops_file = @namespace_or_ops_file.resolve_symbol(name)
126
+ _invoke(*args, **kwargs)
127
+ end
128
+
129
+ def method_missing(name, *args, **kwargs, &block)
130
+ _resolve_method_and_invoke(name, *args, **kwargs)
131
+ end
132
+ end
133
+
134
+ end
@@ -58,25 +58,25 @@ module OpsWalrus
58
58
  Invocation::Success.new(ruby_script_return)
59
59
  end
60
60
  rescue SSHKit::Command::Failed => e
61
- puts "[!] Command failed: #{e.message}"
61
+ App.instance.error "[!] Command failed: #{e.message}"
62
62
  rescue Error => e
63
- $stderr.puts "Error: Ops script crashed."
64
- $stderr.puts e.message
65
- $stderr.puts e.backtrace.join("\n")
63
+ App.instance.error "Error: Ops script crashed."
64
+ App.instance.error e.message
65
+ App.instance.error e.backtrace.take(5).join("\n")
66
66
  Invocation::Error.new(e)
67
67
  rescue => e
68
- $stderr.puts "Unhandled Error: Ops script crashed."
69
- $stderr.puts e.class
70
- $stderr.puts e.message
71
- $stderr.puts e.backtrace.join("\n")
68
+ App.instance.error "Unhandled Error: Ops script crashed."
69
+ App.instance.error e.class
70
+ App.instance.error e.message
71
+ App.instance.error e.backtrace.take(10).join("\n")
72
72
  Invocation::Error.new(e)
73
73
  end
74
74
 
75
75
  if app.debug? && result.failure?
76
- puts "Ops script error details:"
77
- puts "Error: #{result.value}"
78
- puts "Status code: #{result.exit_status}"
79
- puts @entry_point_ops_file.script
76
+ App.instance.debug "Ops script error details:"
77
+ App.instance.debug "Error: #{result.value}"
78
+ App.instance.debug "Status code: #{result.exit_status}"
79
+ App.instance.debug @entry_point_ops_file.script
80
80
  end
81
81
 
82
82
  result