blob: c5ad7c847972be339d4365aecbdc961c8a253a6a [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)
Alexd0391d42019-05-21 18:48:55 -0500102 _code = re.findall(r"[a-zA-Z]+?(?=(?:[0-9]+$)|$)", fqdn.split('.')[0])
savex4448e132018-04-25 15:51:14 +0200103 # check if it is valid and raise if not
104 if _isvalid:
Alexe0c5b9e2019-04-23 18:51:23 -0500105 # try to match it with ones in map
106 _c = _code[0]
107 match = any([r in _c for r in all_roles_map.keys()])
108 if match:
109 # no match, try to find it
110 match = False
111 for r in all_roles_map.keys():
112 _idx = _c.find(r)
113 if _idx > -1:
114 _c = _c[_idx:]
115 match = True
116 break
117 if match:
118 return _c
119 else:
120 return uknown_code
121 else:
122 return uknown_code
savex4448e132018-04-25 15:51:14 +0200123 else:
124 raise ConfigException(_message)
125
savexce010ba2018-04-27 09:49:23 +0200126 def get_nodes_list(self, env, nodes_list):
savex4448e132018-04-25 15:51:14 +0200127 _list = []
128 if env is None:
129 # nothing supplied, use the one in repo
130 try:
Alex Savatieievd48994d2018-12-13 12:13:00 +0100131 if not nodes_list:
132 return []
Alex Savatieiev5118de02019-02-20 15:50:42 -0600133 with open(os.path.join(pkg_dir, nodes_list)) as _f:
savex4448e132018-04-25 15:51:14 +0200134 _list.extend(_f.read().splitlines())
135 except IOError as e:
Alex Savatieievf808cd22019-03-01 13:17:59 -0600136 raise ConfigException("# Error while loading file, '{}': "
savex4448e132018-04-25 15:51:14 +0200137 "{}".format(e.filename, e.strerror))
138 else:
139 _list.extend(self.node_string_to_list(env))
140
141 # validate names
142 _invalid = []
143 _valid = []
144 for idx in range(len(_list)):
145 _name = _list[idx]
146 if not self.validate_name(_name):
147 _invalid.append(_name)
148 else:
149 _valid.append(_name)
150
151 return _valid
152
153
154utils = Utils()