blob: 3952b5f96b2f7e73f6ab67951eb512e5d72be23e [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,
138 value=value,
139 path=short_path
140 )):
141 LOG.warning("Class {} already exists in {}".format(
142 value,
143 short_path
144 ))
Hanna Arhipovae92b66b2021-04-15 19:56:30 +0300145 return
Hanna Arhipova94a8abe2019-08-22 14:11:46 +0300146
147 self.ssh.check_call(
148 "{reclass_tools} add-key classes {value} \
149 /srv/salt/reclass/classes/{path} --merge".format(
150 reclass_tools=self.reclass_tools_cmd,
151 value=value,
152 path=short_path
153 ))
Ekaterina Chernovaa6087342019-08-26 13:14:42 +0300154
Hanna Arhipovae92b66b2021-04-15 19:56:30 +0300155 def delete_class(self, value, short_path):
156 """
157 Shows warning if class doesn't exist
158 :param value: role to delete from 'classes' parameter in the reclass
159 :param short_path: path to reclass yaml file.
160 It takes into account default path where the reclass locates.
161 May look like cluster/*/cicd/control/leader.yml
162 :return: None
163 """
Hanna Arhipova3ea92b22021-07-01 15:44:15 +0300164 current_content = self.get_key('classes', short_path)
165 if value not in current_content:
166 LOG.info("{value} not found in classes in {path}".format(
Hanna Arhipovae92b66b2021-04-15 19:56:30 +0300167 value=value,
168 path=short_path
169 ))
Hanna Arhipova3ea92b22021-07-01 15:44:15 +0300170 return
171
172 new_content = current_content
173 new_content.remove(value)
174
175 self.add_key("classes", new_content, short_path)
Hanna Arhipovae92b66b2021-04-15 19:56:30 +0300176
Ekaterina Chernovaa6087342019-08-26 13:14:42 +0300177 def delete_key(self, key, short_path):
178 """
179 Remove key from the provided file
180
181 :param value: string, parameter which will be deleted
182 :param short_path: string,, path to reclass yaml file.
183 It takes into account default path where the reclass locates.
184 May look like cluster/*/cicd/control/leader.yml
185 :return: None
186 """
187 self.ssh.check_call(
188 "{reclass_tools} del-key {key} \
189 /srv/salt/reclass/classes/{path}".format(
190 reclass_tools=self.reclass_tools_cmd,
191 key=key,
192 path=short_path
193 ))
Hanna Arhipovab7a80bb2020-12-04 15:36:36 +0200194
Hanna Arhipovad33353e2021-02-15 23:14:51 +0200195 def merge_context(self, yaml_context, short_path):
196 """
197 Merge
198
199 :param yaml_context: string, yaml with extra context
200 :param short_path: string, path to reclass yaml file.
201 It takes into account default path where the reclass locates.
202 May look like cluster/*/cicd/control/leader.yml
203 :return: None
204 """
205 tmp_file = "/tmp/extra_context.yaml"
206 with open(tmp_file, "w") as f:
207 f.write(yaml_context)
208
209 self.ssh.upload(tmp_file, tmp_file)
210 self.ssh.check_call(
211 "{reclass_tools} merge-context {yaml} \
212 /srv/salt/reclass/classes/{path}".format(
213 reclass_tools=self.reclass_tools_cmd,
214 yaml=tmp_file,
215 path=short_path
216 ))
217
Hanna Arhipovab7a80bb2020-12-04 15:36:36 +0200218 def commit(self, text_commit):
219 self.ssh.check_call(
220 "cd /srv/salt/reclass; git add -u && git commit --allow-empty "
221 "-m '{text}'".format(text=text_commit))