escli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +10 -0
- data/bin/escli +5 -0
- data/bin/setup +8 -0
- data/escli.gemspec +34 -0
- data/lib/canzea/cli/canzea.rb +323 -0
- data/lib/canzea/cli/escli.rb +207 -0
- data/lib/canzea/commands/add-env.rb +64 -0
- data/lib/canzea/commands/apply-config.rb +50 -0
- data/lib/canzea/commands/config-git-commit.rb +78 -0
- data/lib/canzea/commands/ecosystem/ecosystem.rb +66 -0
- data/lib/canzea/commands/ecosystem/resources.rb +82 -0
- data/lib/canzea/commands/gen-user.rb +22 -0
- data/lib/canzea/commands/get-catalog.rb +46 -0
- data/lib/canzea/commands/login.rb +50 -0
- data/lib/canzea/commands/prepare-plan.rb +82 -0
- data/lib/canzea/commands/push-config.rb +283 -0
- data/lib/canzea/commands/register-metadata.rb +79 -0
- data/lib/canzea/commands/remote-bootstrap.rb +38 -0
- data/lib/canzea/commands/remote-run.rb +37 -0
- data/lib/canzea/commands/update-config.rb +26 -0
- data/lib/canzea/config.rb +35 -0
- data/lib/canzea/core/audit.rb +86 -0
- data/lib/canzea/core/prepare-environment.rb +194 -0
- data/lib/canzea/core/registry.rb +191 -0
- data/lib/canzea/core/ssh-base-cmd-class.rb +103 -0
- data/lib/canzea/core/template-runner.rb +41 -0
- data/lib/canzea/core/trace-component.rb +171 -0
- data/lib/canzea/core/trace-runner.rb +108 -0
- data/lib/canzea/environment.rb +6 -0
- data/lib/canzea/helper-run-class.rb +89 -0
- data/lib/canzea/plan-step-class.rb +210 -0
- data/lib/canzea/registry.rb +12 -0
- data/lib/canzea/version.rb +3 -0
- metadata +201 -0
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
require 'base64'
|
4
|
+
require 'openssl'
|
5
|
+
|
6
|
+
class Registry
|
7
|
+
def getKeyValues (root)
|
8
|
+
uri = URI.parse(ENV["CONSUL_URL"] + "/v1/kv/#{root}?recurse=true")
|
9
|
+
http = prepareHttp(uri)
|
10
|
+
|
11
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
12
|
+
resp = http.request(request)
|
13
|
+
|
14
|
+
if ( Integer(resp.code) != 200 )
|
15
|
+
puts "-- KEY VALUE NOT FOUND! " + root
|
16
|
+
abort("Problem reading registry, response code #{resp.code}")
|
17
|
+
else
|
18
|
+
response = []
|
19
|
+
result = JSON.parse(resp.body)
|
20
|
+
result.each() do |item|
|
21
|
+
response.push({item["Key"] => Base64.decode64(item["Value"])})
|
22
|
+
end
|
23
|
+
return JSON.generate(response)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def getKeyValue (key)
|
28
|
+
|
29
|
+
uri = URI.parse(ENV["CONSUL_URL"] + "/v1/kv/#{key}")
|
30
|
+
http = prepareHttp(uri)
|
31
|
+
|
32
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
33
|
+
resp = http.request(request)
|
34
|
+
|
35
|
+
if Integer(resp.code) != 200
|
36
|
+
puts "-- KEY VALUE NOT FOUND! " + key
|
37
|
+
abort("Problem reading registry, response code #{resp.code}")
|
38
|
+
end
|
39
|
+
|
40
|
+
result = JSON.parse(resp.body)
|
41
|
+
return Base64.decode64(result[0]["Value"])
|
42
|
+
end
|
43
|
+
|
44
|
+
def setKeyValue (root, key, value)
|
45
|
+
|
46
|
+
uri = URI.parse(ENV["CONSUL_URL"] + "/v1/kv/#{root}/#{key}")
|
47
|
+
http = prepareHttp(uri)
|
48
|
+
|
49
|
+
request = Net::HTTP::Put.new(uri.request_uri)
|
50
|
+
request.body = "#{value}";
|
51
|
+
resp = http.request(request)
|
52
|
+
|
53
|
+
if Integer(resp.code) != 200
|
54
|
+
puts "-- KEY VALUE NOT SAVED! #{root} #{key}"
|
55
|
+
abort("Problem adding to registry, response code #{resp.code}")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def exists (key)
|
60
|
+
uri = URI.parse(ENV["CONSUL_URL"] + "/v1/kv/#{key}")
|
61
|
+
http = prepareHttp(uri)
|
62
|
+
|
63
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
64
|
+
resp = http.request(request)
|
65
|
+
|
66
|
+
if Integer(resp.code) == 200
|
67
|
+
return true
|
68
|
+
else
|
69
|
+
return false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def deleteDirectory (root)
|
74
|
+
uri = URI.parse(ENV["CONSUL_URL"] + "/v1/kv/#{root}?recurse=true")
|
75
|
+
http = prepareHttp(uri)
|
76
|
+
|
77
|
+
request = Net::HTTP::Delete.new(uri.request_uri)
|
78
|
+
resp = http.request(request)
|
79
|
+
|
80
|
+
if Integer(resp.code) != 200
|
81
|
+
puts "-- KEY NOT DELETED! " + root
|
82
|
+
abort("Response code #{resp.code}")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def registerDirectory (root)
|
87
|
+
uri = URI.parse(ENV["CONSUL_URL"] + "/v1/kv/#{root}?dir=true")
|
88
|
+
http = prepareHttp(uri)
|
89
|
+
|
90
|
+
request = Net::HTTP::Put.new(uri.request_uri)
|
91
|
+
resp = http.request(request)
|
92
|
+
|
93
|
+
if Integer(resp.code) > 202
|
94
|
+
puts "-- KEY DIRECTORY NOT SAVED! #{root}"
|
95
|
+
abort("Problem adding to registry, response code #{resp.code}")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def register (root, key, value)
|
100
|
+
setKeyValue root, key, value
|
101
|
+
end
|
102
|
+
|
103
|
+
def getSecret (key)
|
104
|
+
|
105
|
+
uri = URI.parse(ENV["VAULT_URL"] + "/v1/secret/#{key}")
|
106
|
+
http = prepareHttpForVault(uri)
|
107
|
+
|
108
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
109
|
+
request['X-Vault-Token'] = ENV["VAULT_TOKEN"]
|
110
|
+
resp = http.request(request)
|
111
|
+
|
112
|
+
if Integer(resp.code) != 200
|
113
|
+
puts "-- UNABLE TO GET SECRET! #{key}"
|
114
|
+
abort("Problem getting secret from vault, response code #{resp.code}")
|
115
|
+
end
|
116
|
+
return JSON.parse(resp.body)['data']
|
117
|
+
end
|
118
|
+
|
119
|
+
def setVaultRecord (key, value)
|
120
|
+
|
121
|
+
uri = URI.parse(ENV["VAULT_URL"] + "/v1/#{key}")
|
122
|
+
http = prepareHttpForVault(uri)
|
123
|
+
|
124
|
+
request = Net::HTTP::Put.new(uri.request_uri)
|
125
|
+
request['Content-Type'] = 'application/json'
|
126
|
+
request['X-Vault-Token'] = ENV["VAULT_TOKEN"]
|
127
|
+
request.body = "#{value}";
|
128
|
+
resp = http.request(request)
|
129
|
+
|
130
|
+
if Integer(resp.code) != 204
|
131
|
+
puts "-- VAULT RECORD NOT SAVED! #{key}"
|
132
|
+
abort("Problem adding to vault, response code #{resp.code}")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def setSecret (key, value)
|
137
|
+
|
138
|
+
uri = URI.parse(ENV["VAULT_URL"] + "/v1/secret/#{key}")
|
139
|
+
http = prepareHttpForVault(uri)
|
140
|
+
|
141
|
+
request = Net::HTTP::Put.new(uri.request_uri)
|
142
|
+
request['Content-Type'] = 'application/json'
|
143
|
+
request['X-Vault-Token'] = ENV["VAULT_TOKEN"]
|
144
|
+
request.body = "#{value}";
|
145
|
+
resp = http.request(request)
|
146
|
+
|
147
|
+
if Integer(resp.code) != 204
|
148
|
+
puts "-- SECRET NOT SAVED! #{key}"
|
149
|
+
abort("Problem adding to vault, response code #{resp.code}")
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def prepareHttp (uri)
|
154
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
155
|
+
|
156
|
+
if (Canzea::config[:consul_tls])
|
157
|
+
pemCert = File.read(Canzea::config[:consul_tls_cert_file])
|
158
|
+
pemKey = File.read(Canzea::config[:consul_tls_key_file])
|
159
|
+
|
160
|
+
http.use_ssl = true
|
161
|
+
http.ca_file = Canzea::config[:consul_tls_ca_file]
|
162
|
+
http.cert = OpenSSL::X509::Certificate.new(pemCert)
|
163
|
+
http.key = OpenSSL::PKey::RSA.new(pemKey)
|
164
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
165
|
+
# http.set_debug_output($stdout)
|
166
|
+
http.ssl_version = :SSLv23
|
167
|
+
end
|
168
|
+
|
169
|
+
return http
|
170
|
+
end
|
171
|
+
|
172
|
+
def prepareHttpForVault (uri)
|
173
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
174
|
+
|
175
|
+
if (Canzea::config[:consul_tls])
|
176
|
+
pemCert = File.read(Canzea::config[:vault_tls_cert_file])
|
177
|
+
pemKey = File.read(Canzea::config[:vault_tls_key_file])
|
178
|
+
|
179
|
+
http.use_ssl = true
|
180
|
+
http.ca_file = Canzea::config[:consul_tls_ca_file]
|
181
|
+
http.cert = OpenSSL::X509::Certificate.new(pemCert)
|
182
|
+
http.key = OpenSSL::PKey::RSA.new(pemKey)
|
183
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
184
|
+
# http.set_debug_output($stdout)
|
185
|
+
http.ssl_version = :SSLv23
|
186
|
+
end
|
187
|
+
|
188
|
+
return http
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# canzea --role=operatingsystem --solution=centos --remote --hostname=192.34.56.119 --privateKey=/var/go/.ssh/id_rsa_digitalocean
|
2
|
+
|
3
|
+
require 'net/ssh'
|
4
|
+
require 'net/sftp'
|
5
|
+
require 'json'
|
6
|
+
require 'openssl'
|
7
|
+
require 'base64'
|
8
|
+
|
9
|
+
class RemoteCall
|
10
|
+
def initialize ()
|
11
|
+
@log = Logger.new(Canzea::config[:logging_root] + '/plans.log')
|
12
|
+
end
|
13
|
+
|
14
|
+
def exec (hostname, privateKey, cmd, ref = "")
|
15
|
+
|
16
|
+
@username = "root"
|
17
|
+
|
18
|
+
@log.info(" R [#{ref}] COMMAND: #{cmd}")
|
19
|
+
|
20
|
+
begin
|
21
|
+
Net::SSH.start(hostname, @username, :paranoid => false, :keys => [privateKey]) do |ssh|
|
22
|
+
|
23
|
+
chan = ssh.open_channel do |channel|
|
24
|
+
channel.request_pty
|
25
|
+
channel.env("DIGITAL_OCEAN_API_KEY", ENV['DIGITAL_OCEAN_API_KEY'])
|
26
|
+
channel.env("VAULT_TOKEN", ENV['VAULT_TOKEN'])
|
27
|
+
channel.env("CONSUL_URL", ENV['CONSUL_URL'])
|
28
|
+
channel.env("WORK_DIR", ENV['WORK_DIR'])
|
29
|
+
channel.env("ES_REF", ref)
|
30
|
+
channel.exec(cmd) do |ch, success|
|
31
|
+
abort "could not execute command" unless success
|
32
|
+
|
33
|
+
channel.on_data do |ch, data|
|
34
|
+
puts data
|
35
|
+
|
36
|
+
data.sub(/\n/, '').scan(/.{1,80}/).each do | line |
|
37
|
+
@log.info(" R [#{ref}] STDOUT: #{line}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
channel.on_request("exit-status") do |ch, data|
|
42
|
+
exit_code = data.read_long
|
43
|
+
@log.info(" R [#{ref}] Exit status: #{exit_code}")
|
44
|
+
if (exit_code == 0)
|
45
|
+
else
|
46
|
+
abort()
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
channel.on_close do |ch|
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
chan.wait
|
55
|
+
end
|
56
|
+
rescue
|
57
|
+
@log.info(" R ABORTED!")
|
58
|
+
raise
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def encrypt (contents, publicKey)
|
63
|
+
pubkey_pem = File.read publicKey
|
64
|
+
key = OpenSSL::PKey::RSA.new pubkey_pem
|
65
|
+
output = Base64.urlsafe_encode64 key.public_encrypt contents
|
66
|
+
puts output
|
67
|
+
end
|
68
|
+
|
69
|
+
def decrypt (contents, privateKey)
|
70
|
+
privkey_pem = File.read privateKey
|
71
|
+
key = OpenSSL::PKey::RSA.new privkey_pem
|
72
|
+
output = key.private_decrypt Base64.urlsafe_decode64 contents
|
73
|
+
puts output
|
74
|
+
end
|
75
|
+
|
76
|
+
# Secure copy - use the public key to encrypt the contents before sent across
|
77
|
+
#
|
78
|
+
def put (hostname, privateKey, localFile, remoteFile = nil)
|
79
|
+
|
80
|
+
@username = "root"
|
81
|
+
|
82
|
+
puts "Uploading #{localFile} to #{remoteFile}"
|
83
|
+
@log.info(" R : Uploading to #{hostname}")
|
84
|
+
@log.info(" R : Uploading #{localFile} to #{remoteFile}")
|
85
|
+
Net::SSH.start(hostname, @username, :paranoid => false, :keys => [privateKey]) do |ssh|
|
86
|
+
ssh.sftp.upload!(localFile, remoteFile)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def get (hostname, privateKey, remoteFile, localFile = nil)
|
91
|
+
|
92
|
+
@username = "root"
|
93
|
+
|
94
|
+
@log.info(" R : Getting from #{hostname}")
|
95
|
+
@log.info(" R : Getting file #{remoteFile}")
|
96
|
+
|
97
|
+
Net::SSH.start(hostname, @username, :paranoid => false, :keys => [privateKey]) do |ssh|
|
98
|
+
ssh.sftp.download!(remoteFile, localFile)
|
99
|
+
end
|
100
|
+
@log.info(" R : Saved to #{localFile}")
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'mustache'
|
3
|
+
|
4
|
+
|
5
|
+
module ViewHelpers
|
6
|
+
# {{#tf_name}}name{{/tf_name}}
|
7
|
+
def tf_name(name)
|
8
|
+
self[name].sub '.', '-'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Template < Mustache
|
13
|
+
include ViewHelpers
|
14
|
+
|
15
|
+
def processAndWriteToFile (template, output, parameters)
|
16
|
+
contents = process template, parameters
|
17
|
+
File.write(output, contents)
|
18
|
+
end
|
19
|
+
|
20
|
+
def process (template, parameters)
|
21
|
+
self.template_file = template
|
22
|
+
ENV.each_pair do |k, v|
|
23
|
+
self[k] = v
|
24
|
+
end
|
25
|
+
parameters.each_pair do |k, v|
|
26
|
+
self[k] = v
|
27
|
+
end
|
28
|
+
return self.render
|
29
|
+
end
|
30
|
+
|
31
|
+
def processString (string, parameters)
|
32
|
+
self.template = string
|
33
|
+
ENV.each_pair do |k, v|
|
34
|
+
self[k] = v
|
35
|
+
end
|
36
|
+
parameters.each_pair do |k, v|
|
37
|
+
self[k] = v
|
38
|
+
end
|
39
|
+
return self.render
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'open3'
|
3
|
+
require 'stringio'
|
4
|
+
require 'logger'
|
5
|
+
require 'canzea/core/audit'
|
6
|
+
|
7
|
+
|
8
|
+
def time_diff_milli(start, finish)
|
9
|
+
(finish - start) * 1000.0
|
10
|
+
end
|
11
|
+
|
12
|
+
def handleIO(stillOpen, ioArray, io, log)
|
13
|
+
if ioArray.include?(io)
|
14
|
+
begin
|
15
|
+
log.write(io.readpartial(4096))
|
16
|
+
rescue EOFError
|
17
|
+
stillOpen.delete_if{|s| s == io}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class ManagedError < StandardError
|
23
|
+
end
|
24
|
+
|
25
|
+
class Worker
|
26
|
+
@test = false
|
27
|
+
|
28
|
+
def initialize ()
|
29
|
+
@log = Logger.new(Canzea::config[:logging_root] + '/plans.log')
|
30
|
+
end
|
31
|
+
|
32
|
+
def test (t)
|
33
|
+
@test = t
|
34
|
+
end
|
35
|
+
|
36
|
+
def find(command, list = [])
|
37
|
+
audit = Audit.new false
|
38
|
+
|
39
|
+
@log.info(" FIND: " + command)
|
40
|
+
|
41
|
+
File.foreach(command) { |l|
|
42
|
+
if ( l.start_with?('## ') )
|
43
|
+
@log.info "#{lines + 1} Label: " + l
|
44
|
+
elsif ( l.start_with?('#') )
|
45
|
+
elsif ( /\S/ !~ l )
|
46
|
+
elsif ( l.chomp.end_with?(".sh") && !l.chomp.end_with?(".atomic.sh") && !l.include?("cp ") && !l.include?("chmod") )
|
47
|
+
@log.info(" [#{ref}] RECURSE: " + l)
|
48
|
+
|
49
|
+
workingDir = "#{Pathname.new(Canzea::config[:catalog_location]).realpath}"
|
50
|
+
|
51
|
+
Dir.chdir(workingDir) {
|
52
|
+
|
53
|
+
newCommand = "#{Pathname.new(l.chomp).realpath}"
|
54
|
+
|
55
|
+
lines = find newCommand, list
|
56
|
+
}
|
57
|
+
else
|
58
|
+
list.push l
|
59
|
+
end
|
60
|
+
}
|
61
|
+
return list
|
62
|
+
end
|
63
|
+
|
64
|
+
def run(command, start, lines, statusIndicator = false, ref = "" )
|
65
|
+
audit = Audit.new false
|
66
|
+
|
67
|
+
@log.info(" [#{ref}] HANDLING: " + command)
|
68
|
+
|
69
|
+
File.foreach(command) { |l|
|
70
|
+
if ( l.start_with?('## ') )
|
71
|
+
@log.info "#{lines + 1} Label: " + l
|
72
|
+
elsif ( l.start_with?('#') )
|
73
|
+
elsif ( /\S/ !~ l )
|
74
|
+
elsif ( l.chomp.end_with?(".sh") && !l.chomp.end_with?(".atomic.sh") && !l.include?("cp ") && !l.include?("chmod") )
|
75
|
+
@log.info(" [#{ref}] RECURSE: " + l)
|
76
|
+
|
77
|
+
workingDir = "#{Pathname.new(Canzea::config[:catalog_location]).realpath}"
|
78
|
+
|
79
|
+
Dir.chdir(workingDir){
|
80
|
+
|
81
|
+
newCommand = "#{Pathname.new(l.chomp).realpath}"
|
82
|
+
|
83
|
+
lines = run newCommand, start, lines
|
84
|
+
}
|
85
|
+
else
|
86
|
+
|
87
|
+
if ( (lines + 1) < start )
|
88
|
+
@log.info(" [#{ref}] Skipping : #{lines + 1} #{l}")
|
89
|
+
lines += 1
|
90
|
+
next
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
audit.start( "#{lines + 1 }", l.chomp)
|
95
|
+
|
96
|
+
@log.info(" [#{ref}] #{(lines + 1).to_s.rjust(2, "0")} : " + l)
|
97
|
+
|
98
|
+
if @test == false
|
99
|
+
t1 = Time.now
|
100
|
+
|
101
|
+
begin
|
102
|
+
workingDir = "#{Pathname.new(Canzea::config[:catalog_location]).realpath}"
|
103
|
+
|
104
|
+
puts "-- Executing [#{workingDir}] #{l}"
|
105
|
+
Dir.chdir(workingDir){
|
106
|
+
Open3.popen3(l) {|stdin, stdout, stderr, wait_thr|
|
107
|
+
pid = wait_thr.pid # pid of the started process.
|
108
|
+
|
109
|
+
log_w = StringIO.new
|
110
|
+
|
111
|
+
stillOpen = [stdout, stderr]
|
112
|
+
while !stillOpen.empty?
|
113
|
+
fhs = select(stillOpen, nil, nil, nil)
|
114
|
+
handleIO(stillOpen, fhs[0], stdout, log_w)
|
115
|
+
handleIO(stillOpen, fhs[0], stderr, log_w)
|
116
|
+
end
|
117
|
+
|
118
|
+
exit_status = wait_thr.value # wait for it to finish
|
119
|
+
|
120
|
+
log_w.close_write
|
121
|
+
|
122
|
+
output = log_w.string
|
123
|
+
|
124
|
+
begin
|
125
|
+
output.split(/\n/).each do | line |
|
126
|
+
puts "-- #{line}"
|
127
|
+
end
|
128
|
+
rescue => exception
|
129
|
+
puts "-- WARNING : Unable to parse output, exception: #{exception.to_s}"
|
130
|
+
end
|
131
|
+
|
132
|
+
puts "-- Exit Status = #{exit_status}"
|
133
|
+
|
134
|
+
@log.info("STDOUT #{output}")
|
135
|
+
|
136
|
+
@log.info("Exit Status = #{exit_status}")
|
137
|
+
|
138
|
+
# if exit status is failure then exit right away
|
139
|
+
|
140
|
+
t2 = Time.now
|
141
|
+
|
142
|
+
msecs = time_diff_milli t1, t2
|
143
|
+
|
144
|
+
audit.complete("#{lines + 1}", l.chomp, exit_status.exitstatus, msecs, output)
|
145
|
+
|
146
|
+
if (statusIndicator)
|
147
|
+
audit.status("#{lines + 1}", l.chomp, exit_status.exitstatus, msecs, output)
|
148
|
+
end
|
149
|
+
|
150
|
+
if exit_status.exitstatus != 0
|
151
|
+
abort()
|
152
|
+
end
|
153
|
+
}
|
154
|
+
}
|
155
|
+
rescue => exception
|
156
|
+
msecs = time_diff_milli t1, Time.now
|
157
|
+
audit.complete("#{lines + 1}", l.chomp, "-1", msecs, exception.to_s)
|
158
|
+
raise
|
159
|
+
end
|
160
|
+
else
|
161
|
+
puts "-- TEST [#{lines + 1}] FOUND: " + l
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
lines += 1
|
167
|
+
}
|
168
|
+
return lines
|
169
|
+
|
170
|
+
end
|
171
|
+
end
|