blob: 5a4c552147bf300f7b931a896ffe62d8bf734642 [file] [log] [blame]
savex4448e132018-04-25 15:51:14 +02001import os
2import re
Alex Savatieiev63576832019-02-27 15:46:26 -06003import subprocess
savex4448e132018-04-25 15:51:14 +02004
Alexe0c5b9e2019-04-23 18:51:23 -05005from cfg_checker.common.const import all_roles_map, uknown_code
Alex Savatieiev5118de02019-02-20 15:50:42 -06006from cfg_checker.common.exception import ConfigException
savex4448e132018-04-25 15:51:14 +02007
Alex Savatieiev5118de02019-02-20 15:50:42 -06008pkg_dir = os.path.dirname(__file__)
9pkg_dir = os.path.join(pkg_dir, os.pardir, os.pardir)
10pkg_dir = os.path.normpath(pkg_dir)
11pkg_dir = os.path.abspath(pkg_dir)
savex4448e132018-04-25 15:51:14 +020012
13
Alex Savatieiev63576832019-02-27 15:46:26 -060014def shell(command):
15 _ps = subprocess.Popen(
16 command.split(),
17 stdout=subprocess.PIPE
18 ).communicate()[0].decode()
19
20 return _ps
21
22
Alex26b8a8c2019-10-09 17:09:07 -050023def merge_dict(source, destination):
24 """
25 Dict merger, thanks to vincent
26 http://stackoverflow.com/questions/20656135/python-deep-merge-dictionary-data
27
28 >>> a = { 'first' : { 'all_rows' : { 'pass' : 'dog', 'number' : '1' } } }
29 >>> b = { 'first' : { 'all_rows' : { 'fail' : 'cat', 'number' : '5' } } }
30 >>> merge(b, a) == {
31 'first': {
32 'all_rows': {
33 'pass': 'dog',
34 'fail': 'cat',
35 'number': '5'
36 }
37 }
38 }
39 True
40 """
41 for key, value in source.items():
42 if isinstance(value, dict):
43 # get node or create one
44 node = destination.setdefault(key, {})
45 merge_dict(value, node)
46 else:
47 destination[key] = value
48
49 return destination
50
51
savex4448e132018-04-25 15:51:14 +020052class Utils(object):
53 @staticmethod
54 def validate_name(fqdn, message=False):
55 """
56 Function that tries to validate node name.
57 Checks if code contains letters, has '.' in it,
58 roles map contains code's role
59
60 :param fqdn: node FQDN name to supply for the check
61 :param message: True if validate should return error check message
62 :return: False if checks failed, True if all checks passed
63 """
Alex Savatieievf808cd22019-03-01 13:17:59 -060064 _message = "# Validation passed"
savex4448e132018-04-25 15:51:14 +020065
66 def _result():
67 return (True, _message) if message else True
68
69 # node role code checks
Alexd0391d42019-05-21 18:48:55 -050070 _code = re.findall(r"[a-zA-Z]+", fqdn.split('.')[0])
savex4448e132018-04-25 15:51:14 +020071 if len(_code) > 0:
72 if _code[0] in all_roles_map:
73 return _result()
74 else:
75 # log warning here
Alex Savatieievf808cd22019-03-01 13:17:59 -060076 _message = "# Node code is unknown, '{}'. " \
77 "# Please, update map".format(_code)
savex4448e132018-04-25 15:51:14 +020078 else:
79 # log warning here
Alex Savatieievf808cd22019-03-01 13:17:59 -060080 _message = "# Node name is invalid, '{}'".format(fqdn)
savex4448e132018-04-25 15:51:14 +020081
82 # put other checks here
83
84 # output result
85 return _result()
86
87 @staticmethod
88 def node_string_to_list(node_string):
89 # supplied var should contain node list
90 # if there is no ',' -> use space as a delimiter
91 if node_string is not None:
92 if node_string.find(',') < 0:
93 return node_string.split(' ')
94 else:
95 return node_string.split(',')
96 else:
97 return []
98
99 def get_node_code(self, fqdn):
100 # validate
101 _isvalid, _message = self.validate_name(fqdn, message=True)
Alex2e213b22019-12-05 10:40:29 -0600102 _code = re.findall(
103 r"[a-zA-Z]+?(?=(?:[0-9]+$)|(?:\-+?)|(?:\_+?)|$)",
104 fqdn.split('.')[0]
105 )
savex4448e132018-04-25 15:51:14 +0200106 # check if it is valid and raise if not
107 if _isvalid:
Alexe0c5b9e2019-04-23 18:51:23 -0500108 # try to match it with ones in map
109 _c = _code[0]
110 match = any([r in _c for r in all_roles_map.keys()])
111 if match:
112 # no match, try to find it
113 match = False
114 for r in all_roles_map.keys():
115 _idx = _c.find(r)
116 if _idx > -1:
117 _c = _c[_idx:]
118 match = True
119 break
120 if match:
121 return _c
122 else:
123 return uknown_code
124 else:
125 return uknown_code
savex4448e132018-04-25 15:51:14 +0200126 else:
127 raise ConfigException(_message)
128
Alexe9908f72020-05-19 16:04:53 -0500129 def get_nodes_list(self, nodes_list, env_sting=None):
savex4448e132018-04-25 15:51:14 +0200130 _list = []
Alexe9908f72020-05-19 16:04:53 -0500131 if env_sting is None:
savex4448e132018-04-25 15:51:14 +0200132 # nothing supplied, use the one in repo
133 try:
Alex Savatieievd48994d2018-12-13 12:13:00 +0100134 if not nodes_list:
135 return []
Alexe9908f72020-05-19 16:04:53 -0500136 with open(nodes_list) as _f:
savex4448e132018-04-25 15:51:14 +0200137 _list.extend(_f.read().splitlines())
138 except IOError as e:
Alex Savatieievf808cd22019-03-01 13:17:59 -0600139 raise ConfigException("# Error while loading file, '{}': "
savex4448e132018-04-25 15:51:14 +0200140 "{}".format(e.filename, e.strerror))
141 else:
Alexe9908f72020-05-19 16:04:53 -0500142 _list.extend(self.node_string_to_list(env_sting))
savex4448e132018-04-25 15:51:14 +0200143
144 # validate names
145 _invalid = []
146 _valid = []
147 for idx in range(len(_list)):
148 _name = _list[idx]
149 if not self.validate_name(_name):
150 _invalid.append(_name)
151 else:
152 _valid.append(_name)
153
Alexe9908f72020-05-19 16:04:53 -0500154 return _valid, _invalid
savex4448e132018-04-25 15:51:14 +0200155
156
157utils = Utils()