razorrisk-cassini-utilities-cassid 0.8.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,149 @@
1
+ # encoding: utf-8
2
+
3
+
4
+ # ##########################################################################
5
+ #
6
+ # Copyright (c) 2019 Razor Risk Technologies Pty Limited. All rights reserved.
7
+ #
8
+ # ##########################################################################
9
+
10
+ # ##########################################################
11
+ # requires
12
+
13
+ require 'win32/service'
14
+ require 'razor_risk/core/diagnostics/logger'
15
+
16
+ # ##########################################################
17
+ # modules
18
+
19
+ module RazorRisk
20
+ module Cassini
21
+ module Utilities
22
+ module CassiD
23
+
24
+ # ##########################################################
25
+ # Service Controler
26
+
27
+ class ServiceController
28
+ include ::RazorRisk::Core::Diagnostics::Logger
29
+ module Constants
30
+ ServiceOptions = {
31
+ host: nil,
32
+ service_type: Win32::Service::WIN32_OWN_PROCESS,
33
+ start_type: Win32::Service::AUTO_START,
34
+ error_control: Win32::Service::ERROR_NORMAL,
35
+ dependencies: nil,
36
+ }
37
+ ServiceStopCommand = 'stop'
38
+ end
39
+
40
+ def initialize name
41
+ @name = check_parameter name, :name, type: ::String
42
+ end
43
+
44
+ def stoppable?
45
+ Win32::Service.status(
46
+ @name
47
+ ).controls_accepted.include?(
48
+ Constants::ServiceStopCommand
49
+ )
50
+ end
51
+
52
+ def exists?
53
+ Win32::Service.exists? @name
54
+ end
55
+
56
+ def register display_name, description, working_directory, script_path, config_path, ruby_path, *args
57
+
58
+ if exists?
59
+ log :warning, "Service '#{@name}' already exists"
60
+ return false
61
+ end
62
+
63
+ check_parameter display_name, :display_name, type: ::String
64
+ check_parameter description, :description, type: ::String
65
+ check_parameter working_directory, :working_directory, type: ::String
66
+ check_parameter script_path, :script_path, type: ::String
67
+ check_parameter config_path, :config_path, type: ::String
68
+ check_parameter args, :args, type: [ ::String ]
69
+
70
+ working_directory = File.expand_path(working_directory)
71
+ # TODO: Check if absolute, make relatve to working?
72
+
73
+ cmd = []
74
+ cmd << ruby_path
75
+ cmd << '-C' << working_directory
76
+ cmd << script_path
77
+ cmd << config_path
78
+ cmd << '--ruby-path' << ruby_path
79
+ cmd += args
80
+ cmd = cmd * ' '
81
+
82
+ options = Constants::ServiceOptions.merge(
83
+ service_name: @name,
84
+ description: description,
85
+ binary_path_name: cmd,
86
+ display_name: display_name,
87
+ )
88
+ Win32::Service.create(options)
89
+ end
90
+
91
+ def unregister
92
+
93
+ unless exists?
94
+ log :warning, "Service '#{@name}' does not exist"
95
+ return false
96
+ end
97
+
98
+ Win32::Service.stop(@name) if stoppable?
99
+ Win32::Service.delete(@name)
100
+ end
101
+
102
+ def start
103
+ unless exists?
104
+ log :warning, "Service '#{@name}' does not exist"
105
+ return false
106
+ end
107
+
108
+ Win32::Service.start(@name)
109
+
110
+ while 'start pending' == Win32::Service.status(@name).current_state
111
+ sleep 1
112
+ end
113
+ sleep 1
114
+
115
+ 'running' == Win32::Service.status(@name).current_state
116
+ end
117
+
118
+ def stop
119
+ unless exists?
120
+ log :warning, "Service '#{@name}' does not exist"
121
+ return false
122
+ end
123
+
124
+ if 'stopped' == Win32::Service.status(@name).current_state
125
+ log :warning, "Service '#{@name}' already stopped"
126
+ return false
127
+ end
128
+
129
+ unless stoppable?
130
+ log :warning, "Service '#{@name}' cannot be stopped"
131
+ return false
132
+ end
133
+
134
+ Win32::Service.stop(@name)
135
+ end
136
+ end
137
+
138
+
139
+ # ##########################################################
140
+ # modules
141
+
142
+ end # module CassiD
143
+ end # module Utilities
144
+ end # module Cassini
145
+ end # module RazorRisk
146
+
147
+ # ############################## end of file ############################# #
148
+
149
+
@@ -0,0 +1,460 @@
1
+ # encoding: UTF-8
2
+
3
+ # ######################################################################## #
4
+ # File: razor_risk/cassini/utilities/cassid/validations.rb
5
+ #
6
+ # Purpose: Validations
7
+ #
8
+ # Created: 23rd February 2018
9
+ # Updated: 2nd July 2018
10
+ #
11
+ # Author: Matthew Wilson
12
+ #
13
+ # Copyright (c) 2018, Razor Risk Technologies Pty Ltd
14
+ # All rights reserved.
15
+ #
16
+ # ######################################################################## #
17
+
18
+
19
+ require 'razor_risk/cassini/utilities/cassid/constants'
20
+
21
+ require 'razor_risk/core/filesystem/find_relative_file'
22
+
23
+ require 'razor_risk/core/diagnostics/logger'
24
+
25
+ =begin
26
+ =end
27
+
28
+ module RazorRisk
29
+ module Cassini
30
+ module Utilities
31
+ module CassiD
32
+
33
+ module Validations
34
+
35
+ include ::Pantheios
36
+ include ::RazorRisk::Core::Diagnostics::Logger
37
+
38
+ module Internal_
39
+
40
+ def self.check_keys_of_ name, h, required, optional
41
+
42
+ trace ParamNames[ :name, :h, :required, :optional ], name, h, required, optional
43
+
44
+ unless ::Hash === h
45
+
46
+ log :warning, "The value of the '#{name}' node is not a hash"
47
+
48
+ return false
49
+ end
50
+
51
+ actual = h.keys
52
+
53
+ required.each do |rk|
54
+
55
+ unless actual.include? rk
56
+
57
+ log :warning, "The key '#{name}' does not contain the required key '#{rk}'"
58
+
59
+ return false
60
+ end
61
+ end
62
+
63
+ actual.each do |k|
64
+
65
+ unless (required + optional).include? k
66
+
67
+ log :warning, "The key '#{name}' contains an unsupported key '#{k}'"
68
+
69
+ return false
70
+ end
71
+ end
72
+
73
+ true
74
+ end
75
+
76
+ def self.check_microservices(h)
77
+
78
+ trace ParamNames[ :h ], h
79
+
80
+ case microservices = h['microservices']
81
+ when nil
82
+
83
+ log :warning, "no microservices specified"
84
+
85
+ return false
86
+ when ::Hash
87
+
88
+ ;
89
+ else
90
+
91
+ log :warning, "'microservices' element has wrong type #{microservices.class}, when it should be a #{::Hash}"
92
+
93
+ return false
94
+ end
95
+
96
+
97
+ case stock = microservices['stock']
98
+ when nil
99
+
100
+ log :warning, "no stock microservices specified"
101
+
102
+ return false
103
+ end
104
+
105
+ # now ensure that all services - stock and otherwise - are
106
+ # properly configured:
107
+
108
+ microservices.each do |category, services|
109
+
110
+ case services
111
+ when ::Hash
112
+
113
+ ;
114
+ else
115
+
116
+ log :warning, "microservices category '#{category}' must be a #{::Hash}"
117
+
118
+ return false
119
+ end
120
+
121
+ services.each do |name, service|
122
+
123
+ case service_path = service['service_path']
124
+ when nil
125
+
126
+ log :warning, "no 'service_path' specified for '#{service}'"
127
+
128
+ return false
129
+ when ::String
130
+
131
+ ;
132
+ else
133
+
134
+ log :warning, "'service_path' element has wrong type #{service_path.class}, when it should be a #{::String}"
135
+
136
+ return false
137
+ end
138
+
139
+ external_route = service['external_route']
140
+ routes = service['routes']
141
+
142
+ if external_route.nil?
143
+
144
+ unless routes.nil?
145
+
146
+ log :warning, "microservice '#{service}' has 'routes' but no 'external_route'"
147
+
148
+ return false
149
+ end
150
+ else
151
+
152
+ if routes.nil? || (::Array === routes && routes.empty?)
153
+
154
+ log :warning, "microservice '#{service}' has 'external_route' but no 'routes'"
155
+
156
+ return false
157
+ else
158
+
159
+ case external_route
160
+ when ::String, ::Regexp
161
+
162
+ ;
163
+ else
164
+
165
+ log :warning, "'external_route' element has wrong type #{external_route.class}, when it should be a #{::Regexp} or #{::String}"
166
+
167
+ return false
168
+ end
169
+
170
+ case routes
171
+ when ::Array
172
+
173
+ unless routes.all? { |h| ::Hash === h }
174
+
175
+ log :warning, "Every item within a 'routes' array must be a #{::Hash}"
176
+
177
+ return false
178
+ end
179
+ else
180
+
181
+ log :warning, "'routes' element has wrong type #{routes.class}, when it should be a #{::Array}"
182
+
183
+ return false
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ return true
191
+ end
192
+
193
+ def self.validate_file_relative_ path, config_path
194
+
195
+ trace ParamNames[ :path, :config_path ], path, config_path
196
+
197
+
198
+ # exists?
199
+
200
+ fe = Recls.stat path
201
+
202
+ return fe if fe
203
+
204
+
205
+ # relative to config file
206
+
207
+ yfe = Recls.stat config_path
208
+ yd = yfe.directory_path
209
+
210
+ p2 = Recls.combine_paths yd, path
211
+
212
+ fe2 = Recls.stat p2
213
+
214
+ return fe2 if fe2
215
+
216
+
217
+ # relative to program file
218
+
219
+ pfe = Recls.stat $0
220
+ pd = pfe.directory_path
221
+
222
+ p3 = Recls.combine_paths pd, path
223
+
224
+ fe3 = Recls.stat p3
225
+
226
+ return fe3 if fe3
227
+
228
+
229
+ # not found
230
+
231
+ nil
232
+ end
233
+ end # module Internal_
234
+
235
+ def valid_configuration? yaml
236
+
237
+ trace ParamNames[ :yaml ], yaml
238
+
239
+ unless ::Hash === yaml
240
+
241
+ log :warning, "object - '#{yaml}' (#{yaml.class}) - is not a #{::Hash}"
242
+
243
+ return false;
244
+ end
245
+
246
+ unless CONFIG_TOP_LEVEL_KEYS.sort == yaml.keys.sort
247
+
248
+ log :warning, "YAML does not contain exactly the top-level keys '#{CONFIG_TOP_LEVEL_KEYS}'"
249
+
250
+ return false;
251
+ end
252
+
253
+ # yaml['cassini']
254
+
255
+ return false unless Internal_.check_keys_of_('cassini', yaml['cassini'], CONFIG_cassini_KEYS_REQ, CONFIG_cassini_KEYS_OPT)
256
+
257
+ return false unless Internal_.check_microservices(yaml['cassini'])
258
+
259
+ return false unless valid_secret_server?(yaml['cassini']['secret_server'])
260
+
261
+
262
+ # yaml['control']
263
+
264
+ return false unless Internal_.check_keys_of_('control', yaml['control'], CONFIG_control_KEYS_REQ, CONFIG_control_KEYS_OPT)
265
+
266
+ # yaml['diagnostics']
267
+
268
+ return false unless Internal_.check_keys_of_('diagnostics', yaml['diagnostics'], CONFIG_diag_KEYS_REQ, CONFIG_diag_KEYS_OPT)
269
+
270
+ # yaml['razor']
271
+
272
+ return false unless Internal_.check_keys_of_('razor', yaml['razor'], CONFIG_razor_KEYS_REQ, CONFIG_razor_KEYS_OPT)
273
+
274
+ yaml
275
+ end
276
+
277
+ def valid_secret_server? ss
278
+
279
+ trace ParamNames[ :ss ], ss
280
+
281
+ case ss
282
+ when nil
283
+
284
+ return true
285
+ when ::Hash
286
+
287
+ host = ss['host']
288
+ port = ss['port']
289
+ secrets_path = ss['secrets_path']
290
+ service_path = ss['service_path']
291
+
292
+ if secrets_path.nil? != service_path.nil?
293
+
294
+ log :warning, "Must define both or neither of 'cassini/secret_server/secrets_path' and 'cassini/secret_server/service_path'"
295
+
296
+ return false
297
+ end
298
+
299
+ unless secrets_path
300
+
301
+ unless port
302
+
303
+ log :warning, "Must specify 'cassini/secret_server/port' if not specifying 'cassini/secret_server/secrets_path' and 'cassini/secret_server/service_path'"
304
+
305
+ return false
306
+ end
307
+ end
308
+
309
+ %w{ host secrets_path service_path }.each do |element_name|
310
+
311
+ case element = ss[element_name]
312
+ when nil
313
+
314
+ ;
315
+ when ::String
316
+
317
+ ;
318
+ else
319
+
320
+ log :warning, "'cassini/secret_server/#{element_name}' must be an #{::String}, but is a #{element.class}"
321
+ end
322
+ end
323
+
324
+ case port
325
+ when nil
326
+
327
+ ;
328
+ when ::Integer
329
+
330
+ ;
331
+ else
332
+
333
+ log :warning, "'cassini/secret_server/port' must be an #{::Integer}, but is a #{port.class}"
334
+ end
335
+ else
336
+
337
+ log :warning, "'cassini/secret_server' must be a #{::Hash} or nil, but is a #{ss.class}"
338
+
339
+ return false
340
+ end
341
+
342
+ true
343
+ end
344
+
345
+ def validate_auth_mode m
346
+
347
+ trace ParamNames[ :m ], m
348
+
349
+ case m.to_s.downcase
350
+ when /auth(?:ori[sz]ation|)[-_]?only/
351
+
352
+ :authorisation_only
353
+ when 'basic'
354
+
355
+ :basic
356
+ when 'jwt'
357
+
358
+ :jwt
359
+ else
360
+
361
+ log :alert, 'currently only supported \'authorisation-only\' and \'basic\' modes'
362
+
363
+ nil
364
+ end
365
+ end
366
+
367
+ def validate_cassini_root_dir rd, *paths
368
+
369
+ trace ParamNames[ :rd, :paths ], rd, paths
370
+
371
+ ::RazorRisk::Core::Filesystem.find_relative_file rd, paths, canonicalise: true
372
+ end
373
+
374
+ def validate_tls t, config_path
375
+
376
+ trace ParamNames[ :t, :config_path ], t, config_path
377
+
378
+ t = nil if ::String === t && t.strip.empty?
379
+
380
+ case t
381
+ when nil
382
+
383
+ return []
384
+ when ::Hash
385
+
386
+ pc = t['cert']
387
+ pk = t['key']
388
+
389
+ return nil if pc.nil?
390
+ return nil if pk.nil?
391
+
392
+ cert = Internal_.validate_file_relative_ pc, config_path
393
+ key = Internal_.validate_file_relative_ pk, config_path
394
+
395
+ return nil unless cert
396
+ return nil unless key
397
+
398
+ return [ cert, key ]
399
+ when ::String
400
+
401
+ cert = Internal_.validate_file_relative_ t, config_path
402
+
403
+ return nil unless cert
404
+
405
+ pk = cert.path[0...(-cert.extension.size)] + '.key'
406
+
407
+ key = Recls.stat(pk)
408
+
409
+ return nil unless key
410
+
411
+ return [ cert, key ]
412
+ else
413
+
414
+ log :warning, "The value of 'tls' is neither a #{::Hash} nor a #{::String}"
415
+
416
+ return nil
417
+ end
418
+ end
419
+
420
+ def validate_clarite_config cc, *paths
421
+
422
+ trace ParamNames[ :cc, :paths ], cc, paths
423
+
424
+ cc = 'clarite_config.xml' if (cc || '').empty?
425
+
426
+ ::RazorRisk::Core::Filesystem.find_relative_file cc, paths, canonicalise: true
427
+ end
428
+
429
+ def validate_executable rr, *paths
430
+
431
+ trace ParamNames[ :rr, :paths ], rr, paths
432
+
433
+ rr = 'RazorRequest.exe' if (rr || '').empty?
434
+
435
+ ::RazorRisk::Core::Filesystem.find_relative_file rr, paths, canonicalise: true
436
+ end
437
+
438
+ def validate_service_path sp, *paths
439
+
440
+ trace ParamNames[ :sp, :paths ], sp, paths
441
+
442
+ ::RazorRisk::Core::Filesystem.find_relative_file sp, paths, canonicalise: true
443
+ end
444
+
445
+ def validate_relative_path p, *paths
446
+
447
+ trace ParamNames[ :p, :paths ], p, paths
448
+
449
+ ::RazorRisk::Core::Filesystem.find_relative_file p, paths, canonicalise: true
450
+ end
451
+
452
+ end # module Validations
453
+ end # module CassiD
454
+ end # module Utilities
455
+ end # module Cassini
456
+ end # module RazorRisk
457
+
458
+ # ############################## end of file ############################# #
459
+
460
+
@@ -0,0 +1,54 @@
1
+ # encoding: UTF-8
2
+
3
+ # ######################################################################## #
4
+ # File: razor_risk/cassini/utilities/cassid/version.rb
5
+ #
6
+ # Purpose: Version for RazorRisk.Cassini.Utilities.CassiD library
7
+ #
8
+ # Created: 23rd February 2018
9
+ # Updated: 24th January 2019
10
+ #
11
+ # Author: Matthew Wilson
12
+ #
13
+ # Copyright (c) 2018, Razor Risk Technologies Pty Ltd
14
+ # All rights reserved.
15
+ #
16
+ # ######################################################################## #
17
+
18
+
19
+ =begin
20
+ =end
21
+
22
+ module RazorRisk
23
+ module Cassini
24
+ module Utilities
25
+
26
+ module CassiD
27
+
28
+ # Current version of the RazorRisk.Cassini.CassiD library
29
+ VERSION = '0.8.11'
30
+
31
+ private
32
+ VERSION_PARTS_ = VERSION.split(/[.]/).collect { |n| n.to_i } # :nodoc:
33
+ public
34
+ # Major version of the RazorRisk.Cassini.CassiD library
35
+ VERSION_MAJOR = VERSION_PARTS_[0] # :nodoc:
36
+ # Minor version of the RazorRisk.Cassini.CassiD library
37
+ VERSION_MINOR = VERSION_PARTS_[1] # :nodoc:
38
+ # Patch version of the RazorRisk.Cassini.CassiD library
39
+ VERSION_PATCH = VERSION_PARTS_[2] # :nodoc:
40
+ # Commit version of the RazorRisk.Cassini.CassiD library
41
+ VERSION_COMMIT = VERSION_PARTS_[3] || 0 # :nodoc:
42
+
43
+
44
+ # The description of the framework
45
+ DESCRIPTION = "Razor Risk's Cassini Web-framework's Initialisation Daemon"
46
+
47
+ end # module CassiD
48
+ end # module Utilities
49
+ end # module Cassini
50
+ end # module RazorRisk
51
+
52
+ # ############################## end of file ############################# #
53
+
54
+
@@ -0,0 +1,11 @@
1
+
2
+ require 'razor_risk/cassini/utilities/cassid/constants'
3
+ require 'razor_risk/cassini/utilities/cassid/configuration'
4
+ require 'razor_risk/cassini/utilities/cassid/validations'
5
+ require 'razor_risk/cassini/utilities/cassid/version'
6
+ require 'razor_risk/cassini/utilities/cassid/main'
7
+ require 'razor_risk/cassini/utilities/cassid/service_controller'
8
+
9
+ # ############################## end of file ############################# #
10
+
11
+