razorrisk-cassini-utilities-cassis 0.7.6
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/bin/razorrisk-cassini-configure +743 -0
- data/lib/razor_risk/cassini/utilities/cassis/configuration_generator.rb +274 -0
- data/lib/razor_risk/cassini/utilities/cassis/constants.rb +41 -0
- data/lib/razor_risk/cassini/utilities/cassis/internal/require/pantheios.rb +16 -0
- data/lib/razor_risk/cassini/utilities/cassis/internal/require/xqsr3/quality/parameter_checking.rb +16 -0
- data/lib/razor_risk/cassini/utilities/cassis/program_utils.rb +86 -0
- data/lib/razor_risk/cassini/utilities/cassis/version.rb +57 -0
- data/lib/razor_risk/cassini/utilities/cassis/zip_utils.rb +236 -0
- data/lib/razor_risk/cassini/utilities/cassis.rb +6 -0
- data/lib/razor_risk/cassini/utilities/configuration/cli.rb +122 -0
- data/lib/razor_risk/cassini/utilities/configuration.rb +16 -0
- data/lib/razor_risk/cassini/utilities/extensions/hash.rb +44 -0
- data/lib/razor_risk/utilities/software/packaging/unzippers/mac_zip.rb +81 -0
- data/lib/razor_risk/utilities/software/packaging/unzippers/seven_zip.rb +82 -0
- data/lib/razor_risk/utilities/software/packaging/unzippers/win_rar.rb +82 -0
- data/lib/razor_risk/utilities/software/packaging/unzippers/win_zip.rb +83 -0
- metadata +116 -0
@@ -0,0 +1,743 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# ######################################################################## #
|
5
|
+
#
|
6
|
+
# The Cassini Installation driver Script
|
7
|
+
#
|
8
|
+
# Copyright (c) 2018, Razor Risk Technologies Pty Ltd All rights reserved.
|
9
|
+
#
|
10
|
+
# ######################################################################## #
|
11
|
+
|
12
|
+
|
13
|
+
# ##########################################################
|
14
|
+
# requires
|
15
|
+
|
16
|
+
require 'razor_risk/cassini/utilities/cassis/configuration_generator'
|
17
|
+
require 'razor_risk/cassini/utilities/cassis/program_utils'
|
18
|
+
require 'razor_risk/cassini/utilities/cassis/version'
|
19
|
+
require 'razor_risk/cassini/utilities/configuration'
|
20
|
+
require 'razor_risk/cassini/utilities/extensions/hash'
|
21
|
+
|
22
|
+
require 'highline/import'
|
23
|
+
require 'nokogiri'
|
24
|
+
require 'recls'
|
25
|
+
|
26
|
+
require 'pathname'
|
27
|
+
require 'securerandom'
|
28
|
+
require 'yaml'
|
29
|
+
|
30
|
+
|
31
|
+
# ##########################################################################
|
32
|
+
# constants
|
33
|
+
|
34
|
+
PROGRAM_VERSION = ::RazorRisk::Cassini::Utilities::CassIS::VERSION
|
35
|
+
DIAGNOSTIC_SEVERITIES = %w{ trace debug informational notice warning failure }
|
36
|
+
|
37
|
+
module Constants
|
38
|
+
CassiniSpecYml = 'cassini.spec.yml'
|
39
|
+
ConfigDir = 'config'
|
40
|
+
CassidYamlFile = 'cassid.yml'
|
41
|
+
SecretsFile = 'secrets.yml'
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# ##########################################################
|
46
|
+
# includes
|
47
|
+
|
48
|
+
include ::RazorRisk::Cassini::Utilities
|
49
|
+
include ::RazorRisk::Cassini::Utilities::CassIS::ProgramUtils
|
50
|
+
|
51
|
+
|
52
|
+
# ##########################################################
|
53
|
+
# classes
|
54
|
+
|
55
|
+
Microservice = CassIS::ConfigurationGenerator::Microservice
|
56
|
+
Route = CassIS::ConfigurationGenerator::Microservice::Route
|
57
|
+
|
58
|
+
class RESTfulMicroservice < Microservice
|
59
|
+
|
60
|
+
def initialize name, external_route, service_path, routes, **options
|
61
|
+
|
62
|
+
super name, external_route, service_path, routes, options.merge({ restful: true })
|
63
|
+
end
|
64
|
+
end # class RESTfulMicroservice
|
65
|
+
|
66
|
+
|
67
|
+
# ##########################################################################
|
68
|
+
# traps
|
69
|
+
|
70
|
+
trap 'SIGINT' do
|
71
|
+
if $writing_init_config
|
72
|
+
$stderr.puts "\n#{basename}: processing cancelled without writing initial configuration file ..."
|
73
|
+
elsif $writing_secrets
|
74
|
+
$stderr.puts "\n#{basename}: processing cancelled without generating secrets ..."
|
75
|
+
elsif $configuring
|
76
|
+
$stderr.puts "\n#{basename}: processing cancelled without writing changes ..."
|
77
|
+
end
|
78
|
+
exit!
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# ##########################################################
|
83
|
+
# functions
|
84
|
+
|
85
|
+
def parse_cassini_spec cassini_spec
|
86
|
+
|
87
|
+
microservices_stock = []
|
88
|
+
microservices_restful = []
|
89
|
+
|
90
|
+
cassini_spec['zips'].each do |microservice, zip|
|
91
|
+
|
92
|
+
if zip['is_cassini_microservice'] and zip['routes']
|
93
|
+
routes = zip['routes'].map do |h|
|
94
|
+
Route.new(
|
95
|
+
h['route'],
|
96
|
+
h['secure'] ? true : false,
|
97
|
+
h['verb'].to_sym
|
98
|
+
) if h['include']
|
99
|
+
end.compact
|
100
|
+
|
101
|
+
if zip['is_restful']
|
102
|
+
microservices_restful << RESTfulMicroservice.new(
|
103
|
+
zip['name'],
|
104
|
+
zip['ex_route'],
|
105
|
+
zip['rel_path'],
|
106
|
+
routes,
|
107
|
+
)
|
108
|
+
else
|
109
|
+
microservices_stock << Microservice.new(
|
110
|
+
zip['name'],
|
111
|
+
zip['ex_route'],
|
112
|
+
zip['rel_path'],
|
113
|
+
routes,
|
114
|
+
)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
CassIS::ConfigurationGenerator
|
120
|
+
.new(stock: microservices_stock, restful: microservices_restful)
|
121
|
+
.generate
|
122
|
+
.to_yaml(line_width: -1)
|
123
|
+
end
|
124
|
+
|
125
|
+
def generate_secrets
|
126
|
+
|
127
|
+
sf = {}
|
128
|
+
sf['secrets'] = {}
|
129
|
+
sf['secrets']['all'] = {}
|
130
|
+
sf['secrets']['all']['SHA256'] = SecureRandom.hex(16)
|
131
|
+
sf['secrets']['all']['HS256'] = SecureRandom.hex(16)
|
132
|
+
sf['secrets']['all']['AES-256-CBC'] = SecureRandom.hex(16)
|
133
|
+
|
134
|
+
sf.to_yaml(line_width: -1)
|
135
|
+
end
|
136
|
+
|
137
|
+
def current_or_nil h, *keys
|
138
|
+
keys.each do |key|
|
139
|
+
return nil unless h.has_key?(key)
|
140
|
+
h = h[key]
|
141
|
+
end
|
142
|
+
return nil if h.to_s =~ /^\*\*\*/
|
143
|
+
h
|
144
|
+
end
|
145
|
+
|
146
|
+
def read_environment_from_clarite_config(clar_conf)
|
147
|
+
|
148
|
+
begin
|
149
|
+
if xml_doc = ::Nokogiri.XML(File.read(clar_conf)) { |c| c.strict }
|
150
|
+
if xml_root = xml_doc.children.first
|
151
|
+
if rzr_svr = xml_root.at_xpath('razor_server')
|
152
|
+
env = rzr_svr['environment'] and return env
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
$stderr.puts "WARNING: The ClarITe configuration file '#{clar_conf}' does not have the element/attribute '/clarite_config/razor_server@environment'"
|
157
|
+
rescue ::Nokogiri::XML::SyntaxError => x
|
158
|
+
$stderr.puts "WARNING: The ClarITe configuration file '#{clar_conf}' does not contain a valid XML document : #{x.message}"
|
159
|
+
end
|
160
|
+
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
|
164
|
+
def make_target_relative target_dir, rel_path
|
165
|
+
abs_path = Recls.combine_paths target_dir, rel_path
|
166
|
+
abs_path = Recls.canonicalise_path abs_path
|
167
|
+
abs_path
|
168
|
+
end
|
169
|
+
|
170
|
+
def update_edit_history properties
|
171
|
+
properties['edit-history'] ||= []
|
172
|
+
properties['edit-history'].unshift "This file reconfigured by '#{basename}' on #{Time.now.strftime('%Y/%m/%d %H:%M:%S.%L')}"
|
173
|
+
end
|
174
|
+
|
175
|
+
def configure_web_services conf, aborter, **options
|
176
|
+
|
177
|
+
begin
|
178
|
+
|
179
|
+
|
180
|
+
aborter.abort("configuration file - '#{cassid_yaml_path}' - does not contain a valid Cassini configuration") unless ::Hash === conf && conf.keys.size >= 4
|
181
|
+
|
182
|
+
properties = conf['properties']
|
183
|
+
cassini = conf['cassini']
|
184
|
+
control = conf['control']
|
185
|
+
diagnostics = conf['diagnostics']
|
186
|
+
razor = conf['razor']
|
187
|
+
|
188
|
+
unless properties && cassini && control && diagnostics && razor
|
189
|
+
|
190
|
+
aborter.abort("configuration file - '#{cassid_yaml_path}' - does not contain a valid Cassini configuration : it does not contain the required top-level elements")
|
191
|
+
end
|
192
|
+
|
193
|
+
# properties
|
194
|
+
update_edit_history properties
|
195
|
+
|
196
|
+
# general
|
197
|
+
|
198
|
+
say('General settings:')
|
199
|
+
|
200
|
+
abs_paths = options[:absolute_paths] || agree("\tDo you want to make all given paths absolute? ") { |q| q.default = false }
|
201
|
+
|
202
|
+
# cassini
|
203
|
+
|
204
|
+
say('Cassini settings:')
|
205
|
+
|
206
|
+
# root directory
|
207
|
+
#
|
208
|
+
current = current_or_nil(cassini, 'root_dir')
|
209
|
+
target_dir = current ? current : Dir.pwd
|
210
|
+
cassini['root_dir'] = target_dir
|
211
|
+
|
212
|
+
# - auth_mode
|
213
|
+
|
214
|
+
choices = %w{ authorisation_only basic jwt }
|
215
|
+
current = current_or_nil(cassini, 'auth_mode')
|
216
|
+
auth_mode = ask("\tAuthorisation mode (one of '#{choices.join('\', \'')}'): ", choices) { |q| q.default = current }
|
217
|
+
|
218
|
+
cassini['auth_mode'] = auth_mode
|
219
|
+
|
220
|
+
# - first_port
|
221
|
+
|
222
|
+
port_range = 1024..65000
|
223
|
+
current = current_or_nil(cassini, 'first_port')
|
224
|
+
current &&= current.to_s
|
225
|
+
first_port = ask("\tSpecify the first port in the range, which is used for the Cassini end-point (in the range #{port_range}) ", Integer) { |q| q.in = port_range; q.default = current }
|
226
|
+
|
227
|
+
cassini['first_port'] = first_port
|
228
|
+
|
229
|
+
# - host
|
230
|
+
|
231
|
+
current = current_or_nil(cassini, 'host') || 'localhost'
|
232
|
+
host = ask("\tSpecify the host name ") { |q| q.default = current }
|
233
|
+
|
234
|
+
cassini['host'] = host
|
235
|
+
|
236
|
+
# - web_server
|
237
|
+
|
238
|
+
choices = %w{ thin webrick }
|
239
|
+
current = current_or_nil(cassini, 'web_server') || 'thin'
|
240
|
+
web_server = ask("\tSpecify the web-server (one of '#{choices.join('\', \'')}'): ", choices) { |q| q.default = current }
|
241
|
+
|
242
|
+
cassini['web_server'] = web_server
|
243
|
+
|
244
|
+
# - web_ui_server
|
245
|
+
|
246
|
+
current = current_or_nil(cassini, 'web_ui_server')
|
247
|
+
web_ui_server = ask("\tSpecify the web-ui-server: ") { |q| q.default = current }
|
248
|
+
|
249
|
+
cassini['web_ui_server'] = web_ui_server
|
250
|
+
|
251
|
+
# - us_multiplier
|
252
|
+
|
253
|
+
usm_range = 1..50
|
254
|
+
current = current_or_nil(cassini, 'us_multiplier') || 5
|
255
|
+
current &&= current.to_s
|
256
|
+
us_multiplier = ask("\tSpecify how many instances of each internal microservice to be started ", Integer) { |q| q.in = usm_range; q.default = current }
|
257
|
+
|
258
|
+
cassini['us_multiplier'] = us_multiplier
|
259
|
+
|
260
|
+
# - JWT
|
261
|
+
#
|
262
|
+
#
|
263
|
+
|
264
|
+
want_jwt = cassini['auth_mode'] == 'jwt'
|
265
|
+
|
266
|
+
unless want_jwt
|
267
|
+
|
268
|
+
cassini['secret_server'] = nil
|
269
|
+
else
|
270
|
+
|
271
|
+
say("\tJWT/Secret Server settings:")
|
272
|
+
|
273
|
+
jwt_host = nil
|
274
|
+
jwt_port = nil
|
275
|
+
jwt_service = nil
|
276
|
+
jwt_secret = nil
|
277
|
+
|
278
|
+
cur_jwt_host = nil
|
279
|
+
cur_jwt_port = nil
|
280
|
+
cur_jwt_service = nil
|
281
|
+
cur_jwt_secret = nil
|
282
|
+
|
283
|
+
# Get the current settings if any
|
284
|
+
case ss = cassini['secret_server']
|
285
|
+
when nil
|
286
|
+
|
287
|
+
;
|
288
|
+
when ::Hash
|
289
|
+
|
290
|
+
cur_jwt_host = current_or_nil(cassini, 'secret_server', 'host')
|
291
|
+
cur_jwt_port = current_or_nil(cassini, 'secret_server', 'port')
|
292
|
+
cur_jwt_secret = current_or_nil(cassini, 'secret_server', 'secrets_path')
|
293
|
+
else
|
294
|
+
|
295
|
+
fail("configuration file - '#{cassid_yaml_path}' - does not contain a valid Cassini configuration : the 'cassini/secret_server' element is not a hash")
|
296
|
+
end
|
297
|
+
|
298
|
+
# Use top level host if not already defined
|
299
|
+
if cur_jwt_host.nil?
|
300
|
+
cur_jwt_host = cassini['host']
|
301
|
+
end
|
302
|
+
|
303
|
+
jwt_host = ask("\t\tSpecify the jwt/secret server host name ") { |q| q.default = cur_jwt_host }
|
304
|
+
|
305
|
+
if cur_jwt_port.nil?
|
306
|
+
|
307
|
+
change_jwt_port = true
|
308
|
+
else
|
309
|
+
|
310
|
+
change_jwt_port = agree("\t\tWould you like to change the jwt/secret port from '#{cur_jwt_port}' (Yes|No) ") { |q| q.default = 'no' }
|
311
|
+
end
|
312
|
+
|
313
|
+
if change_jwt_port
|
314
|
+
|
315
|
+
jwt_port = ask("\t\tSpecify the jwt/secret server port (leave blank to be assigned automatically) ")
|
316
|
+
else
|
317
|
+
|
318
|
+
jwt_port = cur_jwt_port
|
319
|
+
end
|
320
|
+
|
321
|
+
# secret/seed file (for test/uat jwt config)
|
322
|
+
if cur_jwt_secret.nil?
|
323
|
+
cur_jwt_secret = 'config/secrets.yml'
|
324
|
+
end
|
325
|
+
|
326
|
+
ask("\t\tSpecify the jwt/secret server secret(s) configuration path (either absolute, or relative to '#{target_dir}'): ") do |q|
|
327
|
+
|
328
|
+
q.default = cur_jwt_secret
|
329
|
+
q.validate = lambda do |v|
|
330
|
+
|
331
|
+
result = nil
|
332
|
+
|
333
|
+
unless v.strip.empty?
|
334
|
+
|
335
|
+
result ||= Recls.stat(v)
|
336
|
+
result ||= Recls.stat(Recls.combine_paths(target_dir, v))
|
337
|
+
|
338
|
+
result = nil if result && !result.file?
|
339
|
+
end
|
340
|
+
|
341
|
+
jwt_secret = result.to_s
|
342
|
+
|
343
|
+
result
|
344
|
+
end
|
345
|
+
q.responses[:not_valid] = "The given secret configuration path does not specify an existing file or is not relative to '#{target_dir}'"
|
346
|
+
end
|
347
|
+
|
348
|
+
# Cant think of a way around this one yet - maybe should actually check it exists under these conditions
|
349
|
+
jwt_service = 'bin/razorrisk-microservice-secretserver'
|
350
|
+
|
351
|
+
cassini['secret_server'] = {}
|
352
|
+
cassini['secret_server']['host'] = jwt_host
|
353
|
+
cassini['secret_server']['port'] = jwt_port.to_i unless jwt_port.nil? || jwt_port.empty?
|
354
|
+
cassini['secret_server']['service_path'] = jwt_service
|
355
|
+
cassini['secret_server']['secrets_path'] = jwt_secret
|
356
|
+
end
|
357
|
+
|
358
|
+
# - TLS
|
359
|
+
#
|
360
|
+
# This one is a little more complex, because we want to look whether
|
361
|
+
# there's currently any TLS
|
362
|
+
|
363
|
+
has_tls = !cassini['tls'].nil?
|
364
|
+
want_tls = agree("\tDo you wish to use TLS (https://)? (Yes|No) ") { |q| q.default = 'yes' if has_tls }
|
365
|
+
|
366
|
+
unless want_tls
|
367
|
+
|
368
|
+
cassini['tls'] = nil
|
369
|
+
else
|
370
|
+
|
371
|
+
tls_cert = nil
|
372
|
+
tls_pkey = nil
|
373
|
+
|
374
|
+
cur_cert = nil
|
375
|
+
cur_pkey = nil
|
376
|
+
|
377
|
+
case tls = cassini['tls']
|
378
|
+
when nil
|
379
|
+
|
380
|
+
;
|
381
|
+
when ::String
|
382
|
+
|
383
|
+
cur_cert = current_or_nil(cassini, 'tls')
|
384
|
+
when ::Hash
|
385
|
+
|
386
|
+
cur_cert = current_or_nil(cassini, 'tls', 'cert')
|
387
|
+
cur_pkey = current_or_nil(cassini, 'tls', 'key')
|
388
|
+
else
|
389
|
+
|
390
|
+
aborter.abort("configuration file - '#{cassid_yaml_path}' - does not contain a valid Cassini configuration : the 'cassini/tls' element is neither a hash nor a string")
|
391
|
+
end
|
392
|
+
|
393
|
+
|
394
|
+
tls_cert = nil
|
395
|
+
ask("\tSpecify the TLS certificate path: ") do |q|
|
396
|
+
|
397
|
+
q.default = cur_cert
|
398
|
+
q.validate = lambda do |v|
|
399
|
+
|
400
|
+
result = nil
|
401
|
+
|
402
|
+
unless v.strip.empty?
|
403
|
+
|
404
|
+
result ||= Recls.stat(v)
|
405
|
+
result ||= Recls.stat(Recls.combine_paths(target_dir, v))
|
406
|
+
|
407
|
+
result = nil if result && !result.file?
|
408
|
+
end
|
409
|
+
|
410
|
+
tls_cert = result.to_s
|
411
|
+
|
412
|
+
result
|
413
|
+
end
|
414
|
+
q.responses[:not_valid] = "The given certificate file path does not specify an existing file or is not relative to '#{target_dir}'"
|
415
|
+
end
|
416
|
+
|
417
|
+
unless cur_pkey
|
418
|
+
|
419
|
+
fe_cert = Recls.stat(tls_cert)
|
420
|
+
|
421
|
+
%w{ .key .pkey }.each do |ext|
|
422
|
+
|
423
|
+
path_pkey = "#{fe_cert.directory_path}#{fe_cert.stem}#{ext}"
|
424
|
+
|
425
|
+
if cur_pkey = Recls.stat(path_pkey)
|
426
|
+
|
427
|
+
cur_pkey = cur_pkey.to_s
|
428
|
+
|
429
|
+
break
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
tls_pkey = ask("\tSpecify the TLS certificate public key path: ") do |q|
|
435
|
+
|
436
|
+
q.default = cur_pkey
|
437
|
+
q.validate = lambda do |v|
|
438
|
+
|
439
|
+
result = nil
|
440
|
+
|
441
|
+
unless v.strip.empty?
|
442
|
+
|
443
|
+
result ||= Recls.stat(v)
|
444
|
+
result ||= Recls.stat(Recls.combine_paths(target_dir, v))
|
445
|
+
|
446
|
+
result = nil if result && !result.file?
|
447
|
+
end
|
448
|
+
|
449
|
+
result
|
450
|
+
end
|
451
|
+
q.responses[:not_valid] = "The given certificate public key file path does not specify an existing file or is not relative to '#{target_dir}'"
|
452
|
+
end
|
453
|
+
|
454
|
+
cassini['tls'] = {}
|
455
|
+
|
456
|
+
if abs_paths
|
457
|
+
|
458
|
+
tls_cert = make_target_relative(target_dir, tls_cert)
|
459
|
+
tls_pkey = make_target_relative(target_dir, tls_pkey)
|
460
|
+
end
|
461
|
+
|
462
|
+
cassini['tls']['cert'] = tls_cert
|
463
|
+
cassini['tls']['key'] = tls_pkey
|
464
|
+
end
|
465
|
+
|
466
|
+
|
467
|
+
# control
|
468
|
+
|
469
|
+
say('Control settings:')
|
470
|
+
|
471
|
+
# - detach
|
472
|
+
|
473
|
+
current = current_or_nil(control, 'detach')
|
474
|
+
current = current ? 'yes' : 'no' unless current.nil?
|
475
|
+
detach = agree("\tDo you wish to run in detached mode? (Yes|No) ") { |q| q.default = current }
|
476
|
+
|
477
|
+
control['detach'] = detach
|
478
|
+
|
479
|
+
|
480
|
+
# diagnostics
|
481
|
+
|
482
|
+
say('Diagnostic settings:')
|
483
|
+
|
484
|
+
# - benchmark
|
485
|
+
|
486
|
+
current = current_or_nil(diagnostics, 'benchmark')
|
487
|
+
current = current ? 'yes' : 'no' unless current.nil?
|
488
|
+
benchmark = agree("\tDo you wish to conduct benchmark logging? (Yes|No) ") { |q| q.default = current }
|
489
|
+
|
490
|
+
diagnostics['benchmark'] = benchmark
|
491
|
+
|
492
|
+
# - console/threshold
|
493
|
+
|
494
|
+
choices = DIAGNOSTIC_SEVERITIES
|
495
|
+
current = current_or_nil(diagnostics, 'console', 'threshold')
|
496
|
+
thr_console = ask("\tDiagnostic logging threshold for console logging (one of '#{choices.join('\', \'')}'): ", choices) { |q| q.default = current }
|
497
|
+
|
498
|
+
diagnostics['console'] ||= {}
|
499
|
+
diagnostics['console']['threshold'] = thr_console
|
500
|
+
|
501
|
+
# - main/threshold
|
502
|
+
|
503
|
+
choices = DIAGNOSTIC_SEVERITIES
|
504
|
+
current = current_or_nil(diagnostics, 'main', 'threshold')
|
505
|
+
thr_main = ask("\tDiagnostic logging threshold for file logging (one of '#{choices.join('\', \'')}'): ", choices) { |q| q.default = current }
|
506
|
+
|
507
|
+
diagnostics['main'] ||= {}
|
508
|
+
diagnostics['main']['threshold'] = thr_main
|
509
|
+
|
510
|
+
# - directory
|
511
|
+
|
512
|
+
current = current_or_nil(diagnostics, 'directory')
|
513
|
+
diag_dir = nil
|
514
|
+
ask("\tDiagnostic logging directory (either absolute, or relative to '#{target_dir}'): ") do |d|
|
515
|
+
|
516
|
+
d.default = current || 'logs'
|
517
|
+
d.validate = lambda do |v|
|
518
|
+
|
519
|
+
result = nil
|
520
|
+
v = v.strip
|
521
|
+
|
522
|
+
unless v.empty?
|
523
|
+
|
524
|
+
result ||= Recls.stat(v)
|
525
|
+
result ||= Recls.stat(Recls.combine_paths(target_dir, v))
|
526
|
+
|
527
|
+
if result.nil?
|
528
|
+
result = v
|
529
|
+
elsif result.file?
|
530
|
+
result = nil
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
diag_dir = result.to_s
|
535
|
+
result
|
536
|
+
end
|
537
|
+
d.responses[:not_valid] = "The given logging directory does not specify a valid directory path"
|
538
|
+
end
|
539
|
+
diag_dir = make_target_relative(target_dir, diag_dir) if abs_paths
|
540
|
+
diagnostics['directory'] = diag_dir
|
541
|
+
|
542
|
+
# razor
|
543
|
+
|
544
|
+
say('Razor settings:')
|
545
|
+
|
546
|
+
# - clarite_config
|
547
|
+
|
548
|
+
current = current_or_nil(razor, 'clarite_config')
|
549
|
+
clar_conf = nil
|
550
|
+
ask("\tClarITe configuration path (either absolute, or relative to '#{target_dir}'): ") do |q|
|
551
|
+
|
552
|
+
q.default = current
|
553
|
+
q.validate = lambda do |v|
|
554
|
+
|
555
|
+
result = nil
|
556
|
+
|
557
|
+
unless v.strip.empty?
|
558
|
+
|
559
|
+
begin
|
560
|
+
result ||= Recls.stat(v)
|
561
|
+
result ||= Recls.stat(Recls.combine_paths(target_dir, v))
|
562
|
+
|
563
|
+
if !result.nil? and result.directory?
|
564
|
+
result = Recls.stat(
|
565
|
+
Recls.combine_paths(
|
566
|
+
result.path,
|
567
|
+
'clarite_config.xml'
|
568
|
+
)
|
569
|
+
)
|
570
|
+
end
|
571
|
+
|
572
|
+
result = nil if result && !result.file?
|
573
|
+
rescue Errno::EINVAL
|
574
|
+
result = nil
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
clar_conf = result.to_s
|
579
|
+
|
580
|
+
result
|
581
|
+
end
|
582
|
+
q.responses[:not_valid] = "The given ClarITe configuration path does not specify an existing file or is not relative to '#{target_dir}'"
|
583
|
+
end
|
584
|
+
|
585
|
+
clar_conf = make_target_relative(target_dir, clar_conf) if abs_paths
|
586
|
+
|
587
|
+
razor['clarite_config'] = clar_conf
|
588
|
+
|
589
|
+
# - environment
|
590
|
+
|
591
|
+
current = current_or_nil(razor, 'environment')
|
592
|
+
current ||= read_environment_from_clarite_config(Recls.stat(clar_conf).to_s)
|
593
|
+
environment = ask("\tRazor environment name: ") { |q| q.default = current; q.validate = /^[A-Z][-A-Z0-9_$#.]*$/i; q.responses[:not_valid] = "Must supply a valid name" }
|
594
|
+
|
595
|
+
razor['environment'] = environment
|
596
|
+
|
597
|
+
# - executable
|
598
|
+
|
599
|
+
current = current_or_nil(razor, 'executable')
|
600
|
+
executable = nil
|
601
|
+
ask("\tRazor Connectivity Adaptor Executable path (either absolute, or relative to '#{target_dir}'): ") do |q|
|
602
|
+
|
603
|
+
q.default = current
|
604
|
+
q.validate = lambda do |v|
|
605
|
+
|
606
|
+
result = nil
|
607
|
+
|
608
|
+
unless v.strip.empty?
|
609
|
+
|
610
|
+
begin
|
611
|
+
result ||= Recls.stat(v)
|
612
|
+
result ||= Recls.stat(Recls.combine_paths(target_dir, v))
|
613
|
+
|
614
|
+
if !result.nil? and !result.file?
|
615
|
+
dir = result.path
|
616
|
+
result = Recls.stat(
|
617
|
+
Recls.combine_paths(
|
618
|
+
dir,
|
619
|
+
'RazorRequest.exe'
|
620
|
+
)
|
621
|
+
)
|
622
|
+
result ||= Recls.stat(
|
623
|
+
Recls.combine_paths(
|
624
|
+
dir,
|
625
|
+
'RazorRisk.Cassini.ConnectivityAdapter.exe'
|
626
|
+
)
|
627
|
+
)
|
628
|
+
end
|
629
|
+
|
630
|
+
result = nil if result && !result.file?
|
631
|
+
rescue Errno::EINVAL
|
632
|
+
result = nil
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
executable = result.to_s
|
637
|
+
|
638
|
+
result
|
639
|
+
end
|
640
|
+
q.responses[:not_valid] = "The given Razor Connectivity Adaptor Executable path does not specify an existing file or is not relative to '#{target_dir}'"
|
641
|
+
end
|
642
|
+
|
643
|
+
executable = make_target_relative(target_dir, executable) if abs_paths
|
644
|
+
razor['executable'] = executable
|
645
|
+
|
646
|
+
conf.to_yaml(line_width: -1)
|
647
|
+
rescue ::ArgumentError, ::NameError, ::NoMethodError, ::TypeError => x
|
648
|
+
|
649
|
+
$stderr.puts "unexpected exception (#{x.class}): '#{x.message}': #{x.backtrace}"
|
650
|
+
|
651
|
+
raise
|
652
|
+
rescue ::StandardError => x
|
653
|
+
|
654
|
+
$stderr.puts "#{basename}: failed with exception of type #{x.class}: #{x.message}"
|
655
|
+
|
656
|
+
exit 1
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
660
|
+
|
661
|
+
# ##########################################################
|
662
|
+
# main
|
663
|
+
|
664
|
+
options = Configuration::CLI.parse_args ARGV.dup
|
665
|
+
|
666
|
+
# Generate initial config file
|
667
|
+
if options[:gen_init_conf]
|
668
|
+
|
669
|
+
$writing_init_config = true
|
670
|
+
|
671
|
+
# Cassini Spec is required for initial generation
|
672
|
+
unless File.file? Constants::CassiniSpecYml
|
673
|
+
options[:aborter].abort "Cassini Spec file is required to generate initial cassini config"
|
674
|
+
end
|
675
|
+
|
676
|
+
# Do not overwrite existing file
|
677
|
+
path = File.join(Constants::ConfigDir, Constants::CassidYamlFile)
|
678
|
+
options[:aborter].abort "Cassini Config file already exists" if File.file? path
|
679
|
+
|
680
|
+
Dir.mkdir Constants::ConfigDir unless File.directory? Constants::ConfigDir
|
681
|
+
cassini_spec = YAML.load_file(Constants::CassiniSpecYml)
|
682
|
+
initial_config = parse_cassini_spec cassini_spec
|
683
|
+
File.open(path, 'w') { |f| f.write initial_config }
|
684
|
+
|
685
|
+
$writing_init_config = false
|
686
|
+
end
|
687
|
+
|
688
|
+
# Generate Secrets File
|
689
|
+
if options[:gen_secrets]
|
690
|
+
|
691
|
+
$writing_secrets = true
|
692
|
+
|
693
|
+
path = File.join(Constants::ConfigDir, Constants::SecretsFile)
|
694
|
+
|
695
|
+
# Do not overwrite existing file
|
696
|
+
options[:aborter].abort "Secrets file already exists" if File.file? path
|
697
|
+
|
698
|
+
Dir.mkdir Constants::ConfigDir unless File.directory? Constants::ConfigDir
|
699
|
+
secrets = generate_secrets
|
700
|
+
File.open(path, 'w') { |f| f.write secrets }
|
701
|
+
|
702
|
+
$writing_secrets = false
|
703
|
+
end
|
704
|
+
|
705
|
+
# Configure cassini
|
706
|
+
unless options[:no_configuration]
|
707
|
+
|
708
|
+
$configuring = true
|
709
|
+
|
710
|
+
cassid_yaml_path = File.join(Constants::ConfigDir, Constants::CassidYamlFile)
|
711
|
+
cassid_yaml = YAML.load_file(cassid_yaml_path)
|
712
|
+
cassid_yaml = configure_web_services cassid_yaml, options[:aborter], options
|
713
|
+
if agree("\nYou have completed (re)configuration of '#{cassid_yaml_path}'. Do you wish to save your changes (which will overwrite the existing configuration)? (Yes|No) ")
|
714
|
+
File.open(cassid_yaml_path, 'w') { |f| f.write cassid_yaml }
|
715
|
+
end
|
716
|
+
|
717
|
+
$configuring = false
|
718
|
+
end
|
719
|
+
|
720
|
+
if options[:input_config]
|
721
|
+
|
722
|
+
$configuring = true
|
723
|
+
|
724
|
+
cassid_yaml_path = File.join(Constants::ConfigDir, Constants::CassidYamlFile)
|
725
|
+
cassid_yaml = YAML.load_file(cassid_yaml_path)
|
726
|
+
|
727
|
+
input_yaml_path = File.expand_path(options[:input_config])
|
728
|
+
input_yaml = YAML.load_file(input_yaml_path)
|
729
|
+
|
730
|
+
cassid_yaml = cassid_yaml.deep_merge(input_yaml)
|
731
|
+
|
732
|
+
cassid_yaml['properties'] ||= {}
|
733
|
+
update_edit_history cassid_yaml['properties']
|
734
|
+
|
735
|
+
cassid_yaml = cassid_yaml.to_yaml(line_width: -1)
|
736
|
+
File.open(cassid_yaml_path, 'w') { |f| f.write cassid_yaml }
|
737
|
+
|
738
|
+
$configuring = false
|
739
|
+
end
|
740
|
+
|
741
|
+
# ############################## end of file ############################# #
|
742
|
+
|
743
|
+
|