blob: 9b8a8244f0474c8c54e7716018c9a4ea0fcd9bd1 [file] [log] [blame]
Hanna Arhipova94a8abe2019-08-22 14:11:46 +03001# Copyright 2016 Mirantis, Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
Hanna Arhipova3ea92b22021-07-01 15:44:15 +030014import yaml
Hanna Arhipova94a8abe2019-08-22 14:11:46 +030015from tcp_tests import logger
16from tcp_tests.managers.execute_commands import ExecuteCommandsMixin
17
18LOG = logger.logger
19
20
21class ReclassManager(ExecuteCommandsMixin):
22 """docstring for ReclassManager"""
23
24 __config = None
25 __underlay = None
26 reclass_tools_cmd = ". venv-reclass-tools/bin/activate; reclass-tools "
Hanna Arhipovab2522692020-09-23 15:25:11 +030027 tgt = "cfg01" # place where the reclass-tools installed
Hanna Arhipova94a8abe2019-08-22 14:11:46 +030028
29 def __init__(self, config, underlay):
30 self.__config = config
31 self.__underlay = underlay
32
33 reclass_node = [node_name
34 for node_name in self.__underlay.node_names()
35 if self.tgt in node_name]
36 self.ssh = self.__underlay.remote(node_name=reclass_node[0])
37
38 super(ReclassManager, self).__init__(config=config, underlay=underlay)
39
40 def check_existence(self, key):
Hanna Arhipova54fec802020-10-30 12:45:46 +020041 """
42 Returns True if reclass contains that key.
43 :param key: string
44 :return: boolean
45 """
Hanna Arhipova94a8abe2019-08-22 14:11:46 +030046 if key in self.ssh.check_call(
Hanna Arhipovab2522692020-09-23 15:25:11 +030047 "{reclass_tools} get-key {key} /srv/salt/reclass/classes".
48 format(reclass_tools=self.reclass_tools_cmd,
49 key=key)):
Hanna Arhipova94a8abe2019-08-22 14:11:46 +030050 LOG.warning("({}) key already exists in reclass".format(key))
51 return True
52 return False
53
54 def add_key(self, key, value, short_path):
55 """
56 Shows alert if key exists
57
58 :param key: string, parameters which will be added or updated
59 :param value: value of key
60 :param short_path: path to reclass yaml file.
61 It takes into account default path where the reclass locates.
62 May look like cluster/*/cicd/control/leader.yml
63 :return: None
64 """
Hanna Arhipova54fec802020-10-30 12:45:46 +020065
66 value = str(value).replace('"', "'")
67 # let's escape $ symbol for bash-like command
68 value = str(value).replace("$", r"\$")
69
70 # value can contain a space symbol. So value should be in quotes
71 cmd = "{reclass_tools} add-key {key} \"{value}\" \
Hanna Arhipova94a8abe2019-08-22 14:11:46 +030072 /srv/salt/reclass/classes/{path}".format(
73 reclass_tools=self.reclass_tools_cmd,
74 key=key,
75 value=value,
Hanna Arhipova54fec802020-10-30 12:45:46 +020076 path=short_path)
77 LOG.info("Add key to reclass: \n {cmd} ".format(cmd=cmd))
78 self.ssh.check_call(cmd)
Hanna Arhipova94a8abe2019-08-22 14:11:46 +030079
Hanna Arhipova19429962019-10-17 15:16:49 +030080 def get_key(self, key, file_name):
Dmitriy Kruglov07977de2019-09-02 13:15:18 +020081 """Find a key in a YAML
82
83 :param key: string, parameter to add
Hanna Arhipova19429962019-10-17 15:16:49 +030084 :param file_name: name of YAML file to find a key
Dmitriy Kruglov07977de2019-09-02 13:15:18 +020085 :return: str, key if found
86 """
Hanna Arhipova5b0caa52021-07-09 20:23:28 +030087 LOG.debug("Try to get '{key}' key from '{file}' file".format(
Hanna Arhipovab2522692020-09-23 15:25:11 +030088 file=file_name,
89 key=key
90 ))
Hanna Arhipova19429962019-10-17 15:16:49 +030091 request_key = self.ssh.check_call(
Hanna Arhipova3ea92b22021-07-01 15:44:15 +030092 "{reclass_tools} get-key {key} "
93 "/srv/salt/reclass/classes/{file_name}".
Hanna Arhipova19429962019-10-17 15:16:49 +030094 format(reclass_tools=self.reclass_tools_cmd,
95 key=key,
96 file_name=file_name))['stdout']
97
Hanna Arhipova5b0caa52021-07-09 20:23:28 +030098 LOG.debug("Raw output from reclass.get_key {}".format(request_key))
Hanna Arhipova3ea92b22021-07-01 15:44:15 +030099 encoded_request_key = ''.join(request_key).encode(encoding='UTF-8')
Hanna Arhipova5b0caa52021-07-09 20:23:28 +0300100 value = yaml.load(encoded_request_key)
101 LOG.info("From reclass.get_key {}: {}".format(key, value))
102 return value
Dmitriy Kruglov07977de2019-09-02 13:15:18 +0200103
Hanna Arhipova94a8abe2019-08-22 14:11:46 +0300104 def add_bool_key(self, key, value, short_path):
105 """
106 Shows alert if key exists
107
108 :param key: string, parameters which will be added or updated
109 :param value: value of key
110 :param short_path: path to reclass yaml file.
111 It takes into account default path where the reclass locates.
112 May look like cluster/*/cicd/control/leader.yml
113 :return: None
114 """
115 self.check_existence(key)
116 self.ssh.check_call(
117 "{reclass_tools} add-bool-key {key} {value} \
118 /srv/salt/reclass/classes/{path}".format(
119 reclass_tools=self.reclass_tools_cmd,
120 key=key,
121 value=value,
122 path=short_path
123 ), raise_on_err=False)
124
125 def add_class(self, value, short_path):
126 """
127 Shows warning if class exists
128 :param value: role to add to 'classes' parameter in the reclass
129 :param short_path: path to reclass yaml file.
130 It takes into account default path where the reclass locates.
131 May look like cluster/*/cicd/control/leader.yml
132 :return: None
133 """
134 if value in self.ssh.check_call(
135 "{reclass_tools} get-key classes \
136 /srv/salt/reclass/classes/{path}".format(
137 reclass_tools=self.reclass_tools_cmd,
Hanna Arhipova94a8abe2019-08-22 14:11:46 +0300138 path=short_path
139 )):
140 LOG.warning("Class {} already exists in {}".format(
141 value,
142 short_path
143 ))
Hanna Arhipovae92b66b2021-04-15 19:56:30 +0300144 return
Hanna Arhipova94a8abe2019-08-22 14:11:46 +0300145
146 self.ssh.check_call(
147 "{reclass_tools} add-key classes {value} \
148 /srv/salt/reclass/classes/{path} --merge".format(
149 reclass_tools=self.reclass_tools_cmd,
150 value=value,
151 path=short_path
152 ))
Ekaterina Chernovaa6087342019-08-26 13:14:42 +0300153
Hanna Arhipovae92b66b2021-04-15 19:56:30 +0300154 def delete_class(self, value, short_path):
155 """
156 Shows warning if class doesn't exist
157 :param value: role to delete from 'classes' parameter in the reclass
158 :param short_path: path to reclass yaml file.
159 It takes into account default path where the reclass locates.
160 May look like cluster/*/cicd/control/leader.yml
161 :return: None
162 """
Hanna Arhipova3ea92b22021-07-01 15:44:15 +0300163 current_content = self.get_key('classes', short_path)
164 if value not in current_content:
165 LOG.info("{value} not found in classes in {path}".format(
Hanna Arhipovae92b66b2021-04-15 19:56:30 +0300166 value=value,
167 path=short_path
168 ))
Hanna Arhipova3ea92b22021-07-01 15:44:15 +0300169 return
170
171 new_content = current_content
172 new_content.remove(value)
173
174 self.add_key("classes", new_content, short_path)
Hanna Arhipovae92b66b2021-04-15 19:56:30 +0300175
Ekaterina Chernovaa6087342019-08-26 13:14:42 +0300176 def delete_key(self, key, short_path):
177 """
178 Remove key from the provided file
179
180 :param value: string, parameter which will be deleted
181 :param short_path: string,, path to reclass yaml file.
182 It takes into account default path where the reclass locates.
183 May look like cluster/*/cicd/control/leader.yml
184 :return: None
185 """
186 self.ssh.check_call(
187 "{reclass_tools} del-key {key} \
188 /srv/salt/reclass/classes/{path}".format(
189 reclass_tools=self.reclass_tools_cmd,
190 key=key,
191 path=short_path
192 ))
Hanna Arhipovab7a80bb2020-12-04 15:36:36 +0200193
Hanna Arhipovad33353e2021-02-15 23:14:51 +0200194 def merge_context(self, yaml_context, short_path):
195 """
196 Merge
197
198 :param yaml_context: string, yaml with extra context
199 :param short_path: string, path to reclass yaml file.
200 It takes into account default path where the reclass locates.
201 May look like cluster/*/cicd/control/leader.yml
202 :return: None
203 """
204 tmp_file = "/tmp/extra_context.yaml"
205 with open(tmp_file, "w") as f:
206 f.write(yaml_context)
207
208 self.ssh.upload(tmp_file, tmp_file)
209 self.ssh.check_call(
210 "{reclass_tools} merge-context {yaml} \
211 /srv/salt/reclass/classes/{path}".format(
212 reclass_tools=self.reclass_tools_cmd,
213 yaml=tmp_file,
214 path=short_path
215 ))
216
PGlazov7efe3b22022-02-16 17:29:05 +0400217 def create_yaml_with_context(self, yaml_context, short_path):
218 """
219 Create yaml file with context
220
221 :param yaml_context: string, yaml with extra context
222 :param short_path: string, path to reclass yaml file.
223 """
224 tmp_file = "/tmp/extra_context.yaml"
225 with open(tmp_file, "w") as f:
226 f.write(yaml_context)
227
228 self.ssh.upload(tmp_file, tmp_file)
229 self.ssh.check_call(
230 "cat {yaml} > \
231 /srv/salt/reclass/classes/{path}".format(
PGlazov7efe3b22022-02-16 17:29:05 +0400232 yaml=tmp_file,
233 path=short_path
234 ))
235
Hanna Arhipovab7a80bb2020-12-04 15:36:36 +0200236 def commit(self, text_commit):
237 self.ssh.check_call(
238 "cd /srv/salt/reclass; git add -u && git commit --allow-empty "
239 "-m '{text}'".format(text=text_commit))