blob: 304ff75d91a8043abaf6ce1bf34aa39582cda520 [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
Dennis Dmitriev2d60c8e2017-05-12 18:34:01 +030042 self.__port = port
43 self.__host = host
44 self.__api = None
45 self.__user = settings.SALT_USER
46 self.__password = settings.SALT_PASSWORD
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +020047
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +030048 super(SaltManager, self).__init__(config=config, underlay=underlay)
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +020049
50 def install(self, commands):
Dennis Dmitriev2d60c8e2017-05-12 18:34:01 +030051 #if self.__config.salt.salt_master_host == '0.0.0.0':
52 # # Temporary workaround. Underlay should be extended with roles
53 # salt_nodes = self.__underlay.node_names()
54 # self.__config.salt.salt_master_host = \
55 # self.__underlay.host_by_node_name(salt_nodes[0])
Dennis Dmitriev010f4cd2016-11-01 20:43:51 +020056
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030057 self.execute_commands(commands=commands,
58 label="Install and configure salt")
59
60 @property
61 def port(self):
Dennis Dmitriev2d60c8e2017-05-12 18:34:01 +030062 return self.__port
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030063
64 @property
65 def host(self):
Dennis Dmitriev2d60c8e2017-05-12 18:34:01 +030066 if self.__host:
67 return self.__host
68 else:
69 #TODO(ddmitriev): consider to add a check and raise
70 # exception if 'salt_master_host' is not initialized.
71 return self.__config.salt.salt_master_host
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030072
73 @property
74 def api(self):
75 def login():
76 LOG.info("Authentication in Salt API")
Dennis Dmitriev2d60c8e2017-05-12 18:34:01 +030077 self.__api.login(
78 username=self.__user,
79 password=self.__password,
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030080 eauth='pam')
81 return datetime.now()
82
Dennis Dmitriev2d60c8e2017-05-12 18:34:01 +030083 if self.__api:
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030084 if (datetime.now() - self.__session_start).seconds < 5 * 60:
Dennis Dmitriev2d60c8e2017-05-12 18:34:01 +030085 return self.__api
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030086 else:
87 # FIXXME: Change to debug
88 LOG.info("Session's expired")
89 self.__session_start = login()
Dennis Dmitriev2d60c8e2017-05-12 18:34:01 +030090 return self.__api
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030091
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030092 url = "http://{host}:{port}".format(
93 host=self.host, port=self.port)
Dennis Dmitriev2d60c8e2017-05-12 18:34:01 +030094 LOG.info("Connecting to Salt API {0}".format(url))
95 self.__api = Pepper(url)
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030096 self.__session_start = login()
Dennis Dmitriev2d60c8e2017-05-12 18:34:01 +030097 return self.__api
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +030098
99 def local(self, tgt, fun, args=None, kwargs=None):
100 return self.api.local(tgt, fun, args, kwargs, expr_form='compound')
101
102 def local_async(self, tgt, fun, args=None, kwargs=None):
103 return self.api.local_async(tgt, fun, args, kwargs)
104
105 def lookup_result(self, jid):
106 return self.api.lookup_jid(jid)
107
108 def check_result(self, r):
109 if len(r.get('return', [])) == 0:
110 raise LookupError("Result is empty or absent")
111
112 result = r['return'][0]
Dmitry Tyzhnenkobc0f8262017-04-28 15:39:26 +0300113 if len(result) == 0:
114 raise LookupError("Result is empty or absent")
Dmitry Tyzhnenko2b730a02017-04-07 19:31:32 +0300115 LOG.info("Job has result for %s nodes", result.keys())
116 fails = defaultdict(list)
117 for h in result:
118 host_result = result[h]
119 LOG.info("On %s executed:", h)
120 if isinstance(host_result, list):
121 fails[h].append(host_result)
122 continue
123 for t in host_result:
124 task = host_result[t]
125 if task['result'] is False:
126 fails[h].append(task)
127 LOG.error("%s - %s", t, task['result'])
128 else:
129 LOG.info("%s - %s", t, task['result'])
130
131 return fails if fails else None
132
133 def enforce_state(self, tgt, state, args=None, kwargs=None):
134 r = self.local(tgt=tgt, fun='state.sls', args=state)
135 f = self.check_result(r)
136 return r, f
137
138 def enforce_states(self, tgt, state, args=None, kwargs=None):
139 rets = []
140 for s in state:
141 r = self.enforce_state(tgt=tgt, state=s)
142 rets.append(r)
143 return rets
144
145 def run_state(self, tgt, state, args=None, kwargs=None):
146 return self.local(tgt=tgt, fun=state, args=args, kwargs=kwargs), None
147
148 def run_states(self, tgt, state, args=None, kwargs=None):
149 rets = []
150 for s in state:
151 r = self.run_state(tgt=tgt, state=s, args=args, kwargs=kwargs)
152 rets.append(r)
153 return rets