blob: 4a83e124fbd81778de41af0ee7d02cf9a0ddcf7a [file] [log] [blame]
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +02001# 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.
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030014# import time
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +020015
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030016from collections import defaultdict
17
18from datetime import datetime
19from pepper.libpepper import Pepper
20from tcp_tests import settings
21from tcp_tests import logger
22from tcp_tests.managers.execute_commands import ExecuteCommandsMixin
23
24LOG = logger.logger
25
26
27class SaltManager(ExecuteCommandsMixin):
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +020028 """docstring for SaltManager"""
29
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030030 __config = None
31 __underlay = None
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030032 _map = {
33 'enforceState': 'enforce_state',
34 'enforceStates': 'enforce_states',
35 'runState': 'run_state',
36 'runStates': 'run_states',
37 }
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +020038
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030039 def __init__(self, config, underlay, host=None, port='6969'):
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030040 self.__config = config
41 self.__underlay = underlay
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030042 self._port = port
43 self._host = host
44 self._api = None
45 self._user = settings.SALT_USER
46 self._password = settings.SALT_PASSWORD
47 self._salt = self
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +020048
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030049 super(SaltManager, self).__init__(config=config, underlay=underlay)
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +020050
51 def install(self, commands):
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030052 if commands[0].get('do'):
53 self.install2(commands)
54 else:
55 self.install1(commands)
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +020056
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030057 def install1(self, commands):
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030058 if self.__config.salt.salt_master_host == '0.0.0.0':
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030059 # Temporary workaround. Underlay should be extended with roles
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030060 salt_nodes = self.__underlay.node_names()
61 self.__config.salt.salt_master_host = \
62 self.__underlay.host_by_node_name(salt_nodes[0])
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030063
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030064 # self.__underlay.execute_commands(commands=commands,
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030065 # label="Install and configure salt")
66 self.execute_commands(commands=commands,
67 label="Install and configure salt")
68
69 def install2(self, commands):
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030070 if self.__config.salt.salt_master_host == '0.0.0.0':
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030071 # Temporary workaround. Underlay should be extended with roles
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030072 salt_nodes = self.__underlay.node_names()
73 self.__config.salt.salt_master_host = \
74 self.__underlay.host_by_node_name(salt_nodes[0])
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030075
76 # self.run_commands(commands=commands,
77 # label="Install and configure salt")
78 self.execute_commands(commands=commands,
79 label="Install and configure salt")
80
81 @property
82 def port(self):
83 return self._port
84
85 @property
86 def host(self):
87 if self._host:
88 return self._host
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030089 elif self.__config.salt.salt_master_host == '0.0.0.0':
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030090 # Temporary workaround. Underlay should be extended with roles
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030091 salt_nodes = self.__underlay.node_names()
92 self.__config.salt.salt_master_host = \
93 self.__underlay.host_by_node_name(salt_nodes[0])
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030094
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030095 return self.__config.salt.salt_master_host
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030096
97 @property
98 def api(self):
99 def login():
100 LOG.info("Authentication in Salt API")
101 self._api.login(
102 username=self._user,
103 password=self._password,
104 eauth='pam')
105 return datetime.now()
106
107 if self._api:
108 if (datetime.now() - self.__session_start).seconds < 5 * 60:
109 return self._api
110 else:
111 # FIXXME: Change to debug
112 LOG.info("Session's expired")
113 self.__session_start = login()
114 return self._api
115
116 LOG.info("Connect to Salt API")
117 url = "http://{host}:{port}".format(
118 host=self.host, port=self.port)
119 self._api = Pepper(url)
120 self.__session_start = login()
121 return self._api
122
123 def local(self, tgt, fun, args=None, kwargs=None):
124 return self.api.local(tgt, fun, args, kwargs, expr_form='compound')
125
126 def local_async(self, tgt, fun, args=None, kwargs=None):
127 return self.api.local_async(tgt, fun, args, kwargs)
128
129 def lookup_result(self, jid):
130 return self.api.lookup_jid(jid)
131
132 def check_result(self, r):
133 if len(r.get('return', [])) == 0:
134 raise LookupError("Result is empty or absent")
135
136 result = r['return'][0]
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +0300137 if len(result) == 0:
138 raise LookupError("Result is empty or absent")
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +0300139 LOG.info("Job has result for %s nodes", result.keys())
140 fails = defaultdict(list)
141 for h in result:
142 host_result = result[h]
143 LOG.info("On %s executed:", h)
144 if isinstance(host_result, list):
145 fails[h].append(host_result)
146 continue
147 for t in host_result:
148 task = host_result[t]
149 if task['result'] is False:
150 fails[h].append(task)
151 LOG.error("%s - %s", t, task['result'])
152 else:
153 LOG.info("%s - %s", t, task['result'])
154
155 return fails if fails else None
156
157 def enforce_state(self, tgt, state, args=None, kwargs=None):
158 r = self.local(tgt=tgt, fun='state.sls', args=state)
159 f = self.check_result(r)
160 return r, f
161
162 def enforce_states(self, tgt, state, args=None, kwargs=None):
163 rets = []
164 for s in state:
165 r = self.enforce_state(tgt=tgt, state=s)
166 rets.append(r)
167 return rets
168
169 def run_state(self, tgt, state, args=None, kwargs=None):
170 return self.local(tgt=tgt, fun=state, args=args, kwargs=kwargs), None
171
172 def run_states(self, tgt, state, args=None, kwargs=None):
173 rets = []
174 for s in state:
175 r = self.run_state(tgt=tgt, state=s, args=args, kwargs=kwargs)
176 rets.append(r)
177 return rets