1
|
|
|
""" |
2
|
|
|
Basic Needs For Extractor class |
3
|
|
|
|
4
|
|
|
Handling specific needs for Extractor script |
5
|
|
|
""" |
6
|
|
|
# package to facilitate time operations |
7
|
|
|
from datetime import datetime |
8
|
|
|
# package to add support for multi-language (i18n) |
9
|
|
|
import gettext |
10
|
|
|
# package to handle files/folders and related metadata/operations |
11
|
|
|
import os |
12
|
|
|
# package to facilitate working with directories and files |
13
|
|
|
from pathlib import Path |
14
|
|
|
# package to facilitate common operations |
15
|
|
|
from db_extractor.BasicNeeds import BasicNeeds |
16
|
|
|
|
17
|
|
|
|
18
|
|
|
class BasicNeedsForExtractor: |
19
|
|
|
connection_details = None |
20
|
|
|
class_bn = None |
21
|
|
|
locale = None |
22
|
|
|
str_ss = None |
23
|
|
|
srv = None |
24
|
|
|
|
25
|
|
|
def __init__(self, in_language='en_US'): |
26
|
|
|
self.class_bn = BasicNeeds(in_language) |
27
|
|
|
current_script = os.path.basename(__file__).replace('.py', '') |
28
|
|
|
lang_folder = os.path.join(os.path.dirname(__file__), current_script + '_Locale') |
29
|
|
|
self.locale = gettext.translation(current_script, lang_folder, languages=[in_language]) |
30
|
|
|
|
31
|
|
|
def fn_check_inputs_specific(self, in_parameters): |
32
|
|
|
self.class_bn.fn_validate_single_value(in_parameters.input_source_system_file, 'file') |
33
|
|
|
self.class_bn.fn_validate_single_value(in_parameters.input_credentials_file, 'file') |
34
|
|
|
self.class_bn.fn_validate_single_value(in_parameters.input_extracting_sequence_file, 'file') |
35
|
|
|
|
36
|
|
|
def fn_validate_mandatory_properties(self, local_logger, who, properties_parent, in_list): |
37
|
|
|
is_valid = True |
38
|
|
|
for current_property in in_list: |
39
|
|
|
if current_property not in properties_parent: |
40
|
|
|
local_logger.error(self.locale.gettext( |
41
|
|
|
'{who} does not contain "{current_property}" which is mandatory, ' |
42
|
|
|
+ 'therefore extraction sequence will be ignored').replace('{who}', who) |
43
|
|
|
.replace('{current_property}', current_property)) |
44
|
|
|
is_valid = False |
45
|
|
|
return is_valid |
46
|
|
|
|
47
|
|
|
def fn_is_extraction_necessary(self, local_logger, relevant_details): |
48
|
|
|
extraction_is_necessary = False |
49
|
|
|
local_logger.debug(self.locale.gettext('Extract behaviour is set to {extract_behaviour}') |
50
|
|
|
.replace('{extract_behaviour}', relevant_details['extract-behaviour'])) |
51
|
|
|
if relevant_details['extract-behaviour'] == 'skip-if-output-file-exists': |
52
|
|
|
if Path(relevant_details['output-csv-file']).is_file(): |
53
|
|
|
local_logger.debug(self.locale.gettext( |
54
|
|
|
'File {file_name} already exists, ' |
55
|
|
|
+ 'so database extraction will not be performed') |
56
|
|
|
.replace('{file_name}', relevant_details['output-csv-file'])) |
57
|
|
|
else: |
58
|
|
|
extraction_is_necessary = True |
59
|
|
|
local_logger.debug(self.locale.gettext( |
60
|
|
|
'File {file_name} does not exist, ' |
61
|
|
|
+ 'so database extraction has to be performed') |
62
|
|
|
.replace('{file_name}', relevant_details['output-csv-file'])) |
63
|
|
|
elif relevant_details['extract-behaviour'] == 'overwrite-if-output-file-exists': |
64
|
|
|
extraction_is_necessary = True |
65
|
|
|
local_logger.debug(self.locale.gettext('Query extraction probably should be performed ' |
66
|
|
|
+ '(other checks might be required)')) |
67
|
|
|
return extraction_is_necessary |
68
|
|
|
|
69
|
|
|
@staticmethod |
70
|
|
|
def fn_is_extraction_necessary_additional(local_logger, c_ph, c_fo, in_dict): |
71
|
|
|
if in_dict['session']['extract-overwrite-condition'] == 'inherit-from-parent': |
72
|
|
|
in_dict['session']['extract-overwrite-condition'] = \ |
73
|
|
|
in_dict['query']['extract-overwrite-condition'] |
74
|
|
|
elif in_dict['session']['extract-overwrite-condition'] == 'inherit-from-grand-parent': |
75
|
|
|
in_dict['session']['extract-overwrite-condition'] = \ |
76
|
|
|
in_dict['sequence']['extract-overwrite-condition'] |
77
|
|
|
ref_expr = in_dict['session']['extract-overwrite-condition']['reference-expression'] |
78
|
|
|
reference_datetime = c_ph.eval_expression( |
79
|
|
|
local_logger, ref_expr, in_dict['session']['start-iso-weekday']) |
80
|
|
|
child_parent_expressions = c_ph.get_child_parent_expressions() |
81
|
|
|
deviation_original = child_parent_expressions.get(ref_expr.split('_')[1]) |
82
|
|
|
r_dt = datetime.strptime(reference_datetime, |
83
|
|
|
c_ph.output_standard_formats.get(deviation_original)) |
84
|
|
|
return c_fo.fn_get_file_datetime_verdict( |
85
|
|
|
local_logger, in_dict['file']['name'], 'last modified', r_dt) |
86
|
|
|
|
87
|
|
|
@staticmethod |
88
|
|
|
def fn_set_extract_behaviour(in_session): |
89
|
|
|
default_value = 'skip-if-output-file-exists' |
90
|
|
|
allowed_values = [ |
91
|
|
|
'skip-if-output-file-exists', |
92
|
|
|
'overwrite-if-output-file-exists', |
93
|
|
|
] |
94
|
|
|
if ('extract-behaviour' not in in_session) \ |
95
|
|
|
or (in_session['extract-behaviour'] not in allowed_values): |
96
|
|
|
value_to_return = default_value |
97
|
|
|
else: |
98
|
|
|
value_to_return = in_session['extract-behaviour'] |
99
|
|
|
return value_to_return |
100
|
|
|
|
101
|
|
|
def validate_all_json_files(self, local_logger, timer, extracting_sequences): |
102
|
|
|
timer.start() |
103
|
|
|
are_json_files_valid = False |
104
|
|
|
# validation of the extraction sequence file |
105
|
|
|
if self.validate_extraction_sequence_file(local_logger, extracting_sequences): |
106
|
|
|
are_json_files_valid = True |
107
|
|
|
local_logger.debug(self.locale.gettext('Relevant JSON files are valid')) |
108
|
|
|
timer.stop() |
109
|
|
|
return are_json_files_valid |
110
|
|
|
|
111
|
|
|
def validate_all_json_files_current(self, local_logger, timer, in_sequence, seq_index, |
112
|
|
|
in_source_systems, in_user_secrets): |
113
|
|
|
timer.start() |
114
|
|
|
# setting initial checks statuses |
115
|
|
|
can_proceed = {'Extraction' : self.validate_extraction_sequence( |
116
|
|
|
local_logger, in_sequence), 'Source System': False, |
117
|
|
|
'Source System Properties' : False, 'User Secrets': False, |
118
|
|
|
'User Secrets Properties' : False} |
119
|
|
|
# actual check |
120
|
|
|
if can_proceed['Extraction']: |
121
|
|
|
# just few values that's going to be used a lot |
122
|
|
|
srv = { |
123
|
|
|
'vdtp': in_sequence['server-vendor'] + ' ' + in_sequence['server-type'], |
124
|
|
|
'vdr' : in_sequence['server-vendor'], |
125
|
|
|
'typ' : in_sequence['server-type'], |
126
|
|
|
'grp' : in_sequence['server-group'], |
127
|
|
|
'lyr' : in_sequence['server-layer'], |
128
|
|
|
} |
129
|
|
|
can_proceed['Source System'] = self.validate_current_source_system( |
130
|
|
|
local_logger, srv, in_source_systems) |
131
|
|
|
if can_proceed['Source System']: |
132
|
|
|
# variable for source server details |
133
|
|
|
ss = in_source_systems[srv['vdr']][srv['typ']]['Server'][srv['grp']][srv['lyr']] |
134
|
|
|
self.str_ss = '"' + '", "'.join(srv.values()) + '"' |
135
|
|
|
can_proceed['Source System Properties'] = \ |
136
|
|
|
self.validate_current_source_system_properties(local_logger, ss) |
137
|
|
|
can_proceed['User Secrets'] = self.validate_user_secrets_file( |
138
|
|
|
local_logger, srv, in_user_secrets) |
139
|
|
|
srv.update(can_proceed) |
140
|
|
|
srv.update(ss) |
141
|
|
|
srv.update({'ac': in_sequence['account-label']}) |
142
|
|
|
can_proceed['User Secrets Properties'] = \ |
143
|
|
|
self.validate_user_and_establish_connection_details( |
144
|
|
|
local_logger, srv, in_user_secrets) |
145
|
|
|
local_logger.debug(self.locale.gettext('For the sequence number {sequence_number} ' |
146
|
|
|
+ 'the relevant details for database connection ' |
147
|
|
|
+ 'have been verified') |
148
|
|
|
.replace('{sequence_number}', str(seq_index))) |
149
|
|
|
timer.stop() |
150
|
|
|
return can_proceed |
151
|
|
|
|
152
|
|
|
def validate_extraction_query(self, local_logger, timer, in_extraction_sequence): |
153
|
|
|
timer.start() |
154
|
|
|
mandatory_props_q = [ |
155
|
|
|
'input-query-file', |
156
|
|
|
'sessions', |
157
|
|
|
] |
158
|
|
|
is_valid = self.fn_validate_mandatory_properties(local_logger, |
159
|
|
|
self.locale.gettext('Extraction Query'), |
160
|
|
|
in_extraction_sequence, |
161
|
|
|
mandatory_props_q) |
162
|
|
|
timer.stop() |
163
|
|
|
return is_valid |
164
|
|
|
|
165
|
|
|
def validate_extraction_sequence_file(self, local_logger, in_extract_sequence): |
166
|
|
|
is_valid = True |
167
|
|
|
if type(in_extract_sequence) != list: |
168
|
|
|
local_logger.error(self.locale.gettext( |
169
|
|
|
'JSON extraction sequence is not a LIST and must be, therefore cannot be used')) |
170
|
|
|
is_valid = False |
171
|
|
|
elif len(in_extract_sequence) < 1: |
172
|
|
|
local_logger.error(self.locale.gettext( |
173
|
|
|
'Extraction sequence file name is a LIST ' |
174
|
|
|
+ 'but does not contain at least 1 extraction sequence, ' |
175
|
|
|
+ 'therefore cannot be used')) |
176
|
|
|
is_valid = False |
177
|
|
|
return is_valid |
178
|
|
|
|
179
|
|
|
def validate_extraction_sequence(self, local_logger, in_extraction_sequence): |
180
|
|
|
mandatory_props_e = [ |
181
|
|
|
'server-vendor', |
182
|
|
|
'server-type', |
183
|
|
|
'server-group', |
184
|
|
|
'server-layer', |
185
|
|
|
'account-label', |
186
|
|
|
'queries', |
187
|
|
|
] |
188
|
|
|
is_valid = self.fn_validate_mandatory_properties( |
189
|
|
|
local_logger, self.locale.gettext('Extraction Sequence'), |
190
|
|
|
in_extraction_sequence, mandatory_props_e) |
191
|
|
|
return is_valid |
192
|
|
|
|
193
|
|
|
def validate_query_session(self, local_logger, in_session): |
194
|
|
|
mandatory_properties = [ |
195
|
|
|
'extract-behaviour', |
196
|
|
|
'output-file', |
197
|
|
|
] |
198
|
|
|
is_valid = self.fn_validate_mandatory_properties( |
199
|
|
|
local_logger, self.locale.gettext('Query Session') + ' ' + self.str_ss, |
200
|
|
|
in_session, mandatory_properties) |
201
|
|
|
return is_valid |
202
|
|
|
|
203
|
|
|
def validate_current_source_system_properties(self, local_logger, in_source_system): |
204
|
|
|
mandatory_properties = [ |
205
|
|
|
'ServerName', |
206
|
|
|
'ServerPort', |
207
|
|
|
] |
208
|
|
|
is_valid = self.fn_validate_mandatory_properties( |
209
|
|
|
local_logger, self.locale.gettext('Source System') + ' ' + self.str_ss, |
210
|
|
|
in_source_system, mandatory_properties) |
211
|
|
|
return is_valid |
212
|
|
|
|
213
|
|
|
def validate_current_source_system(self, in_logger, in_seq, in_source_systems): |
214
|
|
|
can_proceed_s = self.fn_validate_mandatory_properties( |
215
|
|
|
in_logger, self.locale.gettext('Source Systems'), |
216
|
|
|
in_source_systems, [in_seq['vdr']]) |
217
|
|
|
can_proceed_s1 = False |
218
|
|
|
if can_proceed_s: |
219
|
|
|
item_checked = in_source_systems[in_seq['vdr']] |
220
|
|
|
can_proceed_s1 = self.fn_validate_mandatory_properties( |
221
|
|
|
in_logger, self.locale.gettext('Source Systems') + ' "' + in_seq['vdr'] + '"', |
222
|
|
|
item_checked, [in_seq['typ']]) |
223
|
|
|
can_proceed_s2 = False |
224
|
|
|
if can_proceed_s1: |
225
|
|
|
item_checked = in_source_systems[in_seq['vdr']][in_seq['typ']]['Server'] |
226
|
|
|
can_proceed_s2 = self.fn_validate_mandatory_properties( |
227
|
|
|
in_logger, self.locale.gettext('Source Systems') + ' "' + in_seq['vdr'] |
228
|
|
|
+ '", "' + in_seq['typ'] + '", "Server" ', |
229
|
|
|
item_checked, [in_seq['grp']]) |
230
|
|
|
can_proceed_s3 = False |
231
|
|
|
if can_proceed_s2: |
232
|
|
|
item_checked = in_source_systems[in_seq['vdr']][in_seq['typ']]['Server'][in_seq['grp']] |
233
|
|
|
can_proceed_s3 = self.fn_validate_mandatory_properties( |
234
|
|
|
in_logger, self.locale.gettext('Source Systems') + ' "' + in_seq['vdr'] |
235
|
|
|
+ '", "' + in_seq['typ'] + '", "' + in_seq['grp'] + '", "Server" ', |
236
|
|
|
item_checked, [in_seq['lyr']]) |
237
|
|
|
return can_proceed_s and can_proceed_s1 and can_proceed_s2 and can_proceed_s3 |
238
|
|
|
|
239
|
|
|
def validate_user_and_establish_connection_details(self, local_logger, in_dc, in_user): |
240
|
|
|
is_valid = False |
241
|
|
|
if in_dc['Source System Properties'] and in_dc['User Secrets']: |
242
|
|
|
# variable with credentials for source server |
243
|
|
|
u = in_user[in_dc['vdr']][in_dc['typ']][in_dc['grp']][in_dc['lyr']][in_dc['ac']] |
244
|
|
|
is_valid = self.validate_user_secrets(local_logger, u) |
245
|
|
|
self.connection_details = { |
246
|
|
|
'server-vendor-and-type': in_dc['vdtp'], |
247
|
|
|
'server-layer' : in_dc['lyr'], |
248
|
|
|
'ServerName' : in_dc['ServerName'], |
249
|
|
|
'ServerPort' : int(in_dc['ServerPort']), |
250
|
|
|
'Username' : u['Username'], |
251
|
|
|
'Name' : u['Name'], |
252
|
|
|
'Password' : u['Password'], |
253
|
|
|
} |
254
|
|
|
return is_valid |
255
|
|
|
|
256
|
|
|
def validate_user_secrets(self, local_logger, in_user_secrets): |
257
|
|
|
mandatory_properties = [ |
258
|
|
|
'Name', |
259
|
|
|
'Username', |
260
|
|
|
'Password', |
261
|
|
|
] |
262
|
|
|
is_valid = self.fn_validate_mandatory_properties(local_logger, |
263
|
|
|
self.locale.gettext('User Secrets') |
264
|
|
|
+ ' ' + self.str_ss, |
265
|
|
|
in_user_secrets, mandatory_properties) |
266
|
|
|
if in_user_secrets['Name'] in ('login', 'Your Full Name Here'): |
267
|
|
|
local_logger.warning( |
268
|
|
|
self.locale.gettext('For {str_user_secrets} your "Name" property ' |
269
|
|
|
+ 'has the default value: "{default_name_value}" ' |
270
|
|
|
+ 'which is unusual') |
271
|
|
|
.replace('{str_user_secrets}', self.str_ss) |
272
|
|
|
.replace('{default_name_value}', in_user_secrets['Name'])) |
273
|
|
|
if in_user_secrets['Username'] in ('usrnme', 'your_username_goes_here'): |
274
|
|
|
local_logger.warning( |
275
|
|
|
self.locale.gettext('For {str_user_secrets} your "Username" property ' |
276
|
|
|
+ 'has the default value: "{default_username_value}" ' |
277
|
|
|
+ 'which is unusual') |
278
|
|
|
.replace('{str_user_secrets}', self.str_ss) |
279
|
|
|
.replace('{default_username_value}', in_user_secrets['Username'])) |
280
|
|
|
if in_user_secrets['Password'] in ('pwd', 'your_password_goes_here'): |
281
|
|
|
local_logger.warning( |
282
|
|
|
self.locale.gettext('For {str_user_secrets} your "Password" property ' |
283
|
|
|
+ 'has the default value: "{default_password_value}" ' |
284
|
|
|
+ 'which is unusual') |
285
|
|
|
.replace('{str_user_secrets}', self.str_ss) |
286
|
|
|
.replace('{default_password_value}', in_user_secrets['Password'])) |
287
|
|
|
return is_valid |
288
|
|
|
|
289
|
|
|
def validate_user_secrets_file(self, local_logger, in_seq, in_user_secrets): |
290
|
|
|
can_proceed_u = self.fn_validate_mandatory_properties( |
291
|
|
|
local_logger, self.locale.gettext('User Secrets'), |
292
|
|
|
in_user_secrets, [in_seq['vdr']]) |
293
|
|
|
can_proceed_u1 = False |
294
|
|
|
if can_proceed_u: |
295
|
|
|
item_checked = in_user_secrets[in_seq['vdr']] |
296
|
|
|
can_proceed_u1 = self.fn_validate_mandatory_properties( |
297
|
|
|
local_logger, self.locale.gettext('User Secrets') + ' "' + in_seq['vdr'] + '"', |
298
|
|
|
item_checked, [in_seq['typ']]) |
299
|
|
|
can_proceed_u2 = False |
300
|
|
|
if can_proceed_u1: |
301
|
|
|
item_checked = in_user_secrets[in_seq['vdr']][in_seq['typ']] |
302
|
|
|
can_proceed_u2 = self.fn_validate_mandatory_properties( |
303
|
|
|
local_logger, self.locale.gettext('User Secrets') + ' "' + in_seq['vdr'] |
304
|
|
|
+ '", "' + in_seq['typ'] + '", "Server" ', |
305
|
|
|
item_checked, [in_seq['grp']]) |
306
|
|
|
can_proceed_u3 = False |
307
|
|
|
if can_proceed_u2: |
308
|
|
|
item_checked = in_user_secrets[in_seq['vdr']][in_seq['typ']][in_seq['grp']] |
309
|
|
|
can_proceed_u3 = self.fn_validate_mandatory_properties( |
310
|
|
|
local_logger, self.locale.gettext('User Secrets') + ' "' + in_seq['vdr'] |
311
|
|
|
+ '", "' + in_seq['typ'] + '", "' |
312
|
|
|
+ in_seq['grp'] + '", "Server" ', |
313
|
|
|
item_checked, [in_seq['lyr']]) |
314
|
|
|
return can_proceed_u and can_proceed_u1 and can_proceed_u2 and can_proceed_u3 |
315
|
|
|
|