Merge "Change PTL informatin in INFO"
[bottlenecks.git] / testsuites / vstf / vstf_scripts / vstf / common / saltstack.py
1 ##############################################################################
2 # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 import os
11 import sys
12 import inspect
13 import logging
14 import salt.client as sclient
15
16 from vstf.common import cmds
17
18 log = logging.getLogger(__name__)
19
20
21 class Mysalt(object):
22     IS_DIR = 1
23     IS_FILE = 2
24     FAILED = -1
25
26     def __init__(self):
27         self.cur_path = os.path.abspath(os.path.dirname(inspect.stack()[1][1]))
28         self.salt_conf = "/etc/salt/master"
29         if not os.path.exists(self.salt_conf):
30             raise Exception("this python must be run on the salt master.")
31         self.pillar_path = str(
32             cmds.execute("grep '^pillar_roots' \
33                     /etc/salt/master -A 2 | sed 1,2d | awk '{print $2}'") + '/')
34         if self.pillar_path == "":
35             log.warning(
36                 "pillar path not found, make sure the pillar_roots configed")
37         else:
38             os.system("mkdir -p " + self.pillar_path)
39
40         self.state_path = str(cmds.execute("grep '^file_roots' \
41             /etc/salt/master -A 2 | sed 1,2d | awk '{print $2}'") + '/')
42         if self.state_path == "":
43             log.warning(
44                 "state path not found, make sure the file_roots configed")
45         else:
46             os.system("mkdir -p " + self.state_path)
47
48         self.salt = sclient.LocalClient()
49
50     def slave_exists(self, host):
51         pslave = "/etc/salt/pki/master/minions/" + host
52         if os.path.exists(pslave):
53             return True
54         else:
55             return False
56
57     def __is_dir_or_file(self, src):
58         if not os.path.exists(src):
59             return self.FAILED
60         if os.path.isdir(src):
61             return self.IS_DIR
62         elif os.path.isfile(src):
63             return self.IS_FILE
64         else:
65             return self.FAILED
66
67     def __copy_target(self, target, flag=""):
68         if not os.path.exists(target):
69             log.error("target %(d)s  not exists.", {'d': target})
70             return False
71
72         if flag == "pillar":
73             dst = self.pillar_path
74         elif flag == "state":
75             dst = self.state_path
76         else:
77             log.error(
78                 "this file or dir not pillar or state, can not support now.")
79             return False
80
81         if self.IS_FILE == self.__is_dir_or_file(target):
82             os.system('cp ' + target + ' ' + dst)
83         else:
84             os.system("cp -r " + target + ' ' + dst)
85         return True
86
87     def copy(self, host, src, dst):
88         """copy file or dir to slave.
89         :src a file or a dir
90         :dst if src is a file, the dst must be like this /home/xx.py, not /home
91         """
92
93         '''check if the host exists on the master'''
94         if not self.slave_exists(host):
95             log.error("the host %(h)s is not held by master, please check.")
96             return False
97
98         '''copy file to salt's file_roots'''
99         if not self.__copy_target(src, "state"):
100             return False
101
102         if self.IS_DIR == self.__is_dir_or_file(src):
103             dir_name = os.path.basename(src)
104             self.salt.cmd(host, "cp.get_dir", ["salt://" + dir_name, dst])
105         elif self.IS_FILE == self.__is_dir_or_file(src):
106             file_name = os.path.basename(src)
107             print self.salt.cmd(host, "cp.get_file", ["salt://" + file_name, dst])
108         else:
109             log.error("not file and not dir, what is it")
110             return False
111         return True
112
113     def __luxuriant_line(self, str, color):
114         if "red" == color:
115             return "\033[22;35;40m" + str + "\033[0m"
116         elif "green" == color:
117             return "\033[22;32;40m" + str + "\033[0m"
118         else:
119             return str
120
121     def result_check(self, ret, host):
122         num_s = 0
123         num_f = 0
124         msg = ""
125         try:
126             for key in ret[host].keys():
127                 if True == ret[host][key]['result']:
128                     num_s += 1
129                 else:
130                     num_f += 1
131                     msg = msg + \
132                         self.__luxuriant_line("Failed %d:\n" % num_f, "red")
133                     msg = msg + "\t" + key + '\n'
134                     msg = msg + \
135                         self.__luxuriant_line("\t%s\n" % ret[host][key]['comment'], "red")
136                     if True == ('retcode' in ret[host][key]['changes']):
137                         msg = msg + \
138                             "RETCODE: %s\n" % (ret[host][key]['changes']['retcode'])
139                     if True == ('stderr' in ret[host][key]['changes']):
140                         msg = msg + \
141                             "STDERR: %s\n" % (ret[host][key]['changes']['stderr'])
142                     if True == ('stdout' in ret[host][key]['changes']):
143                         msg = msg + \
144                             "STDOUT: %s\n" % (ret[host][key]['changes']['stdout'])
145             msg = msg + \
146                 self.__luxuriant_line("total success: %d\n" % num_s, "green")
147             msg = msg + self.__luxuriant_line("failed: %d\n" % num_f, "red")
148         except Exception as e:
149             log.error(
150                 "sorry, thy to check result happend error, <%(e)s>.\nret:%(ret)s", {
151                     'e': e, 'ret': ret})
152             return -1
153         log.info(':\n' + msg)
154         return num_f
155
156     def run_state(self, host, fstate, ext_pillar={}, care_result=True):
157         try:
158             log.info("salt " + host + " state.sls " +
159                      fstate + ' pillar=\'' + str(ext_pillar) + '\'')
160             ret = self.salt.cmd(
161                 host, 'state.sls', [
162                     fstate, 'pillar=' + str(ext_pillar)], 180, 'list')
163         except Exception as e:
164             log.error("try to init host %(host)s happend error: <%(e)s>.",
165                       {'host': host, 'e': e})
166             if True == care_result:
167                 raise e
168
169         if 0 != self.result_check(ret, host) and care_result:
170             sys.exit(-1)
171         return True
172
173     def salt_cmd(self, host, cmd):
174         # import pdb
175         # pdb.set_trace()
176         logging.info("Begin to run cmd %s on %s" % (host, cmd))
177
178         try:
179             ret = self.salt.cmd(host, 'cmd.run', [cmd])
180         except Exception:
181             log.error("Remote salt execute failed.")
182         return ret
183
184     def copy_by_state(self, host, src, state_cmd, **kwargs):
185         '''the src must be a dir, and the state.sls
186         must be the name of the dir name'''
187
188         if not self.slave_exists(host):
189             log.error("the host %(h)s is not held by master, please check.")
190             return False
191
192         if not self.__copy_target(src, "state"):
193             return False
194
195         return self.run_state(host, state_cmd, kwargs, care_result=True)
196
197     def get_master_ip(self, host=None):
198         if not host:
199             ret = cmds.execute(
200                 "grep '^interface:' /etc/salt/master | awk '{print $2}'").strip()
201             return ret
202         try:
203             ret = self.salt.cmd(host, "grains.item", ["master"])[
204                 host]['master']
205         except Exception:
206             log.error("salt happened error when get master ip")
207             return ""
208         return ret
209
210
211 mysalt = Mysalt()